2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
6 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
7 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
9 * Copyright (C) 2012 Intel Corporation. All rights reserved.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
28 #include "core/css/parser/BisonCSSParser.h"
30 #include "CSSValueKeywords.h"
31 #include "RuntimeEnabledFeatures.h"
32 #include "StylePropertyShorthand.h"
33 #include "core/css/CSSArrayFunctionValue.h"
34 #include "core/css/CSSAspectRatioValue.h"
35 #include "core/css/CSSBasicShapes.h"
36 #include "core/css/CSSBorderImage.h"
37 #include "core/css/CSSCanvasValue.h"
38 #include "core/css/CSSCrossfadeValue.h"
39 #include "core/css/CSSCursorImageValue.h"
40 #include "core/css/CSSFontFaceSrcValue.h"
41 #include "core/css/CSSFontFeatureValue.h"
42 #include "core/css/CSSFunctionValue.h"
43 #include "core/css/CSSGradientValue.h"
44 #include "core/css/CSSGridLineNamesValue.h"
45 #include "core/css/CSSGridTemplateValue.h"
46 #include "core/css/CSSImageSetValue.h"
47 #include "core/css/CSSImageValue.h"
48 #include "core/css/CSSInheritedValue.h"
49 #include "core/css/CSSInitialValue.h"
50 #include "core/css/CSSKeyframeRule.h"
51 #include "core/css/CSSKeyframesRule.h"
52 #include "core/css/CSSLineBoxContainValue.h"
53 #include "core/css/CSSPrimitiveValue.h"
54 #include "core/css/CSSPropertySourceData.h"
55 #include "core/css/CSSReflectValue.h"
56 #include "core/css/CSSSVGDocumentValue.h"
57 #include "core/css/CSSSelector.h"
58 #include "core/css/CSSShadowValue.h"
59 #include "core/css/CSSStyleSheet.h"
60 #include "core/css/CSSTimingFunctionValue.h"
61 #include "core/css/CSSTransformValue.h"
62 #include "core/css/CSSUnicodeRangeValue.h"
63 #include "core/css/CSSValueList.h"
64 #include "core/css/CSSValuePool.h"
65 #include "core/css/CSSVariableValue.h"
66 #include "core/css/Counter.h"
67 #include "core/css/HashTools.h"
68 #include "core/css/MediaList.h"
69 #include "core/css/MediaQueryExp.h"
70 #include "core/css/Pair.h"
71 #include "core/css/Rect.h"
72 #include "core/css/StylePropertySet.h"
73 #include "core/css/StyleRule.h"
74 #include "core/css/StyleRuleImport.h"
75 #include "core/css/StyleSheetContents.h"
76 #include "core/css/parser/CSSParserIdioms.h"
77 #include "core/dom/Document.h"
78 #include "core/frame/FrameHost.h"
79 #include "core/frame/PageConsole.h"
80 #include "core/frame/Settings.h"
81 #include "core/html/parser/HTMLParserIdioms.h"
82 #include "core/inspector/InspectorInstrumentation.h"
83 #include "core/rendering/RenderTheme.h"
84 #include "core/svg/SVGParserUtilities.h"
85 #include "platform/FloatConversion.h"
86 #include "wtf/BitArray.h"
87 #include "wtf/HexNumber.h"
88 #include "wtf/text/StringBuffer.h"
89 #include "wtf/text/StringBuilder.h"
90 #include "wtf/text/StringImpl.h"
91 #include "wtf/text/TextEncoding.h"
97 extern int cssyydebug;
100 int cssyyparse(WebCore::BisonCSSParser*);
107 static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
108 static const double MAX_SCALE = 1000000;
110 template <unsigned N>
111 static bool equal(const CSSParserString& a, const char (&b)[N])
113 unsigned length = N - 1; // Ignore the trailing null character
114 if (a.length() != length)
117 return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar*>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length);
120 template <unsigned N>
121 static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
123 unsigned length = N - 1; // Ignore the trailing null character
124 if (a.length() != length)
127 return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length);
130 template <unsigned N>
131 static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N])
133 ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrimitiveValue::CSS_STRING);
134 return equalIgnoringCase(value->string, b);
137 static PassRefPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtr<CSSPrimitiveValue> first, PassRefPtr<CSSPrimitiveValue> second, Pair::IdenticalValuesPolicy identicalValuesPolicy = Pair::DropIdenticalValues)
139 return cssValuePool().createValue(Pair::create(first, second, identicalValuesPolicy));
142 class AnimationParseContext {
144 AnimationParseContext()
145 : m_animationPropertyKeywordAllowed(true)
146 , m_firstAnimationCommitted(false)
147 , m_hasSeenAnimationPropertyKeyword(false)
151 void commitFirstAnimation()
153 m_firstAnimationCommitted = true;
156 bool hasCommittedFirstAnimation() const
158 return m_firstAnimationCommitted;
161 void commitAnimationPropertyKeyword()
163 m_animationPropertyKeywordAllowed = false;
166 bool animationPropertyKeywordAllowed() const
168 return m_animationPropertyKeywordAllowed;
171 bool hasSeenAnimationPropertyKeyword() const
173 return m_hasSeenAnimationPropertyKeyword;
176 void sawAnimationPropertyKeyword()
178 m_hasSeenAnimationPropertyKeyword = true;
182 bool m_animationPropertyKeywordAllowed;
183 bool m_firstAnimationCommitted;
184 bool m_hasSeenAnimationPropertyKeyword;
187 BisonCSSParser::BisonCSSParser(const CSSParserContext& context, UseCounter* counter)
190 , m_id(CSSPropertyInvalid)
192 , m_supportsCondition(false)
193 , m_selectorListForParseSelector(0)
194 , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
195 , m_inParseShorthand(0)
196 , m_currentShorthand(CSSPropertyInvalid)
197 , m_implicitShorthand(false)
198 , m_hasFontFaceOnlyValues(false)
199 , m_hadSyntacticallyValidCSSRule(false)
201 , m_ignoreErrors(false)
202 , m_defaultNamespace(starAtom)
205 , m_ruleHeaderType(CSSRuleSourceData::UNKNOWN_RULE)
206 , m_allowImportRules(true)
207 , m_allowNamespaceDeclarations(true)
208 , m_inViewport(false)
209 , m_useCounter(counter)
215 CSSPropertySourceData::init();
218 BisonCSSParser::~BisonCSSParser()
222 deleteAllValues(m_floatingSelectors);
223 deleteAllValues(m_floatingSelectorVectors);
224 deleteAllValues(m_floatingValueLists);
225 deleteAllValues(m_floatingFunctions);
228 void BisonCSSParser::setupParser(const char* prefix, unsigned prefixLength, const String& string, const char* suffix, unsigned suffixLength)
230 m_tokenizer.setupTokenizer(prefix, prefixLength, string, suffix, suffixLength);
231 m_ruleHasHeader = true;
234 void BisonCSSParser::parseSheet(StyleSheetContents* sheet, const String& string, const TextPosition& startPosition, CSSParserObserver* observer, bool logErrors)
236 setStyleSheet(sheet);
237 m_defaultNamespace = starAtom; // Reset the default namespace.
238 TemporaryChange<CSSParserObserver*> scopedObsever(m_observer, observer);
239 m_logErrors = logErrors && sheet->singleOwnerDocument() && !sheet->baseURL().isEmpty() && sheet->singleOwnerDocument()->frameHost();
240 m_ignoreErrors = false;
241 m_tokenizer.m_lineNumber = 0;
242 m_startPosition = startPosition;
244 m_tokenizer.m_internal = false;
245 setupParser("", string, "");
247 sheet->shrinkToFit();
250 m_lineEndings.clear();
251 m_ignoreErrors = false;
253 m_tokenizer.m_internal = true;
256 PassRefPtr<StyleRuleBase> BisonCSSParser::parseRule(StyleSheetContents* sheet, const String& string)
258 setStyleSheet(sheet);
259 m_allowNamespaceDeclarations = false;
260 setupParser("@-internal-rule ", string, "");
262 return m_rule.release();
265 PassRefPtr<StyleKeyframe> BisonCSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string)
267 setStyleSheet(sheet);
268 setupParser("@-internal-keyframe-rule ", string, "");
270 return m_keyframe.release();
273 PassOwnPtr<Vector<double> > BisonCSSParser::parseKeyframeKeyList(const String& string)
275 setupParser("@-internal-keyframe-key-list ", string, "");
278 return StyleKeyframe::createKeyList(m_valueList.get());
281 bool BisonCSSParser::parseSupportsCondition(const String& string)
283 m_supportsCondition = false;
284 setupParser("@-internal-supports-condition ", string, "");
286 return m_supportsCondition;
289 static inline bool isColorPropertyID(CSSPropertyID propertyId)
291 switch (propertyId) {
292 case CSSPropertyColor:
293 case CSSPropertyBackgroundColor:
294 case CSSPropertyBorderBottomColor:
295 case CSSPropertyBorderLeftColor:
296 case CSSPropertyBorderRightColor:
297 case CSSPropertyBorderTopColor:
298 case CSSPropertyOutlineColor:
299 case CSSPropertyTextLineThroughColor:
300 case CSSPropertyTextOverlineColor:
301 case CSSPropertyTextUnderlineColor:
302 case CSSPropertyWebkitBorderAfterColor:
303 case CSSPropertyWebkitBorderBeforeColor:
304 case CSSPropertyWebkitBorderEndColor:
305 case CSSPropertyWebkitBorderStartColor:
306 case CSSPropertyWebkitColumnRuleColor:
307 case CSSPropertyWebkitTextEmphasisColor:
308 case CSSPropertyWebkitTextFillColor:
309 case CSSPropertyWebkitTextStrokeColor:
311 case CSSPropertyTextDecorationColor:
312 return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
318 static bool parseColorValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
320 ASSERT(!string.isEmpty());
321 bool quirksMode = isQuirksModeBehavior(cssParserMode);
322 if (!isColorPropertyID(propertyId))
324 CSSParserString cssString;
325 cssString.init(string);
326 CSSValueID valueID = cssValueKeywordID(cssString);
327 bool validPrimitive = false;
328 if (valueID == CSSValueWebkitText) {
329 validPrimitive = true;
330 } else if (valueID == CSSValueCurrentcolor) {
331 validPrimitive = true;
332 } else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
333 || (quirksMode && valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText)) {
334 validPrimitive = true;
337 if (validPrimitive) {
338 RefPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID);
339 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
343 if (!BisonCSSParser::fastParseColor(color, string, !quirksMode && string[0] != '#'))
345 RefPtr<CSSValue> value = cssValuePool().createColorValue(color);
346 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
350 static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
352 switch (propertyId) {
353 case CSSPropertyFontSize:
354 case CSSPropertyHeight:
355 case CSSPropertyWidth:
356 case CSSPropertyMinHeight:
357 case CSSPropertyMinWidth:
358 case CSSPropertyPaddingBottom:
359 case CSSPropertyPaddingLeft:
360 case CSSPropertyPaddingRight:
361 case CSSPropertyPaddingTop:
362 case CSSPropertyWebkitLogicalWidth:
363 case CSSPropertyWebkitLogicalHeight:
364 case CSSPropertyWebkitMinLogicalWidth:
365 case CSSPropertyWebkitMinLogicalHeight:
366 case CSSPropertyWebkitPaddingAfter:
367 case CSSPropertyWebkitPaddingBefore:
368 case CSSPropertyWebkitPaddingEnd:
369 case CSSPropertyWebkitPaddingStart:
370 acceptsNegativeNumbers = false;
372 case CSSPropertyShapeMargin:
373 case CSSPropertyShapePadding:
374 acceptsNegativeNumbers = false;
375 return RuntimeEnabledFeatures::cssShapesEnabled();
376 case CSSPropertyBottom:
377 case CSSPropertyLeft:
378 case CSSPropertyMarginBottom:
379 case CSSPropertyMarginLeft:
380 case CSSPropertyMarginRight:
381 case CSSPropertyMarginTop:
382 case CSSPropertyRight:
384 case CSSPropertyWebkitMarginAfter:
385 case CSSPropertyWebkitMarginBefore:
386 case CSSPropertyWebkitMarginEnd:
387 case CSSPropertyWebkitMarginStart:
388 acceptsNegativeNumbers = true;
395 template <typename CharacterType>
396 static inline bool parseSimpleLength(const CharacterType* characters, unsigned length, CSSPrimitiveValue::UnitTypes& unit, double& number)
398 if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
400 unit = CSSPrimitiveValue::CSS_PX;
401 } else if (length > 1 && characters[length - 1] == '%') {
403 unit = CSSPrimitiveValue::CSS_PERCENTAGE;
406 // We rely on charactersToDouble for validation as well. The function
407 // will set "ok" to "false" if the entire passed-in character range does
408 // not represent a double.
410 number = charactersToDouble(characters, length, &ok);
414 static bool parseSimpleLengthValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
416 ASSERT(!string.isEmpty());
417 bool acceptsNegativeNumbers;
419 // In @viewport, width and height are shorthands, not simple length values.
420 if (isCSSViewportParsingEnabledForMode(cssParserMode) || !isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
423 unsigned length = string.length();
425 CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
427 if (string.is8Bit()) {
428 if (!parseSimpleLength(string.characters8(), length, unit, number))
431 if (!parseSimpleLength(string.characters16(), length, unit, number))
435 if (unit == CSSPrimitiveValue::CSS_NUMBER) {
436 bool quirksMode = isQuirksModeBehavior(cssParserMode);
437 if (number && !quirksMode)
439 unit = CSSPrimitiveValue::CSS_PX;
441 if (number < 0 && !acceptsNegativeNumbers)
444 RefPtr<CSSValue> value = cssValuePool().createValue(number, unit);
445 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
449 static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext)
454 switch (propertyId) {
455 case CSSPropertyBorderCollapse: // collapse | separate | inherit
456 if (valueID == CSSValueCollapse || valueID == CSSValueSeparate)
459 case CSSPropertyBorderTopStyle: // <border-style> | inherit
460 case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
461 case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
462 case CSSPropertyBorderLeftStyle:
463 case CSSPropertyWebkitBorderAfterStyle:
464 case CSSPropertyWebkitBorderBeforeStyle:
465 case CSSPropertyWebkitBorderEndStyle:
466 case CSSPropertyWebkitBorderStartStyle:
467 case CSSPropertyWebkitColumnRuleStyle:
468 if (valueID >= CSSValueNone && valueID <= CSSValueDouble)
471 case CSSPropertyBoxSizing:
472 if (valueID == CSSValueBorderBox || valueID == CSSValueContentBox)
475 case CSSPropertyCaptionSide: // top | bottom | left | right | inherit
476 if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom)
479 case CSSPropertyClear: // none | left | right | both | inherit
480 if (valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth)
483 case CSSPropertyDirection: // ltr | rtl | inherit
484 if (valueID == CSSValueLtr || valueID == CSSValueRtl)
487 case CSSPropertyDisplay:
488 // inline | block | list-item | inline-block | table |
489 // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
490 // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none | inherit
491 // flex | inline-flex | -webkit-flex | -webkit-inline-flex | grid | inline-grid | lazy-block
492 if ((valueID >= CSSValueInline && valueID <= CSSValueInlineFlex) || valueID == CSSValueWebkitFlex || valueID == CSSValueWebkitInlineFlex || valueID == CSSValueNone)
494 if (valueID == CSSValueGrid || valueID == CSSValueInlineGrid)
495 return RuntimeEnabledFeatures::cssGridLayoutEnabled();
498 case CSSPropertyEmptyCells: // show | hide | inherit
499 if (valueID == CSSValueShow || valueID == CSSValueHide)
502 case CSSPropertyFloat: // left | right | none | center (for buggy CSS, maps to none)
503 if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone || valueID == CSSValueCenter)
506 case CSSPropertyFontStyle: // normal | italic | oblique | inherit
507 if (valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique)
510 case CSSPropertyImageRendering: // auto | optimizeContrast
511 if (valueID == CSSValueAuto || valueID == CSSValueWebkitOptimizeContrast)
514 case CSSPropertyIsolation: // auto | isolate
515 if (valueID == CSSValueAuto || valueID == CSSValueIsolate)
516 return RuntimeEnabledFeatures::cssCompositingEnabled();
518 case CSSPropertyListStylePosition: // inside | outside | inherit
519 if (valueID == CSSValueInside || valueID == CSSValueOutside)
522 case CSSPropertyListStyleType:
523 // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
524 // for the list of supported list-style-types.
525 if ((valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone)
528 case CSSPropertyObjectFit:
529 if (RuntimeEnabledFeatures::objectFitPositionEnabled()) {
530 if (valueID == CSSValueFill || valueID == CSSValueContain || valueID == CSSValueCover || valueID == CSSValueNone || valueID == CSSValueScaleDown)
534 case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit
535 if (valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble))
538 case CSSPropertyOverflowWrap: // normal | break-word
539 case CSSPropertyWordWrap:
540 if (valueID == CSSValueNormal || valueID == CSSValueBreakWord)
543 case CSSPropertyOverflowX: // visible | hidden | scroll | auto | overlay | inherit
544 if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay)
547 case CSSPropertyOverflowY: // visible | hidden | scroll | auto | overlay | inherit | -webkit-paged-x | -webkit-paged-y
548 if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY)
551 case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit
552 case CSSPropertyPageBreakBefore:
553 case CSSPropertyWebkitColumnBreakAfter:
554 case CSSPropertyWebkitColumnBreakBefore:
555 if (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight)
558 case CSSPropertyPageBreakInside: // avoid | auto | inherit
559 case CSSPropertyWebkitColumnBreakInside:
560 if (valueID == CSSValueAuto || valueID == CSSValueAvoid)
563 case CSSPropertyPointerEvents:
564 // none | visiblePainted | visibleFill | visibleStroke | visible |
565 // painted | fill | stroke | auto | all | bounding-box | inherit
566 if (valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueBoundingBox))
569 case CSSPropertyPosition: // static | relative | absolute | fixed | sticky | inherit
570 if (valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed
571 || (RuntimeEnabledFeatures::cssStickyPositionEnabled() && valueID == CSSValueSticky))
574 case CSSPropertyResize: // none | both | horizontal | vertical | auto
575 if (valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto)
578 case CSSPropertyScrollBehavior: // instant | smooth
579 if (valueID == CSSValueInstant || valueID == CSSValueSmooth)
580 return RuntimeEnabledFeatures::cssomSmoothScrollEnabled();
581 case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit
582 if (valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation)
585 case CSSPropertyTableLayout: // auto | fixed | inherit
586 if (valueID == CSSValueAuto || valueID == CSSValueFixed)
589 case CSSPropertyTextAlignLast:
590 // auto | start | end | left | right | center | justify
591 if (RuntimeEnabledFeatures::css3TextEnabled()
592 && ((valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto))
595 case CSSPropertyTextJustify:
596 // auto | none | inter-word | distribute
597 if (RuntimeEnabledFeatures::css3TextEnabled()
598 && (valueID == CSSValueInterWord || valueID == CSSValueDistribute || valueID == CSSValueAuto || valueID == CSSValueNone))
601 case CSSPropertyTextLineThroughMode:
602 case CSSPropertyTextOverlineMode:
603 case CSSPropertyTextUnderlineMode:
604 if (valueID == CSSValueContinuous || valueID == CSSValueSkipWhiteSpace)
607 case CSSPropertyTextLineThroughStyle:
608 case CSSPropertyTextOverlineStyle:
609 case CSSPropertyTextUnderlineStyle:
610 if (valueID == CSSValueNone || valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDashed || valueID == CSSValueDotDash || valueID == CSSValueDotDotDash || valueID == CSSValueWave)
613 case CSSPropertyTextOverflow: // clip | ellipsis
614 if (valueID == CSSValueClip || valueID == CSSValueEllipsis)
617 case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
618 if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision)
621 case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit
622 if ((valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone)
625 case CSSPropertyTouchActionDelay: // none | script
626 if (RuntimeEnabledFeatures::cssTouchActionDelayEnabled() && (valueID == CSSValueScript || valueID == CSSValueNone))
629 case CSSPropertyVisibility: // visible | hidden | collapse | inherit
630 if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse)
633 case CSSPropertyWebkitAppearance:
634 if ((valueID >= CSSValueCheckbox && valueID <= CSSValueTextarea) || valueID == CSSValueNone)
637 case CSSPropertyWebkitBackfaceVisibility:
638 if (valueID == CSSValueVisible || valueID == CSSValueHidden)
641 case CSSPropertyMixBlendMode:
642 if (RuntimeEnabledFeatures::cssCompositingEnabled() && (valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen
643 || valueID == CSSValueOverlay || valueID == CSSValueDarken || valueID == CSSValueLighten || valueID == CSSValueColorDodge
644 || valueID == CSSValueColorBurn || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference
645 || valueID == CSSValueExclusion || valueID == CSSValueHue || valueID == CSSValueSaturation || valueID == CSSValueColor
646 || valueID == CSSValueLuminosity))
649 case CSSPropertyWebkitBorderFit:
650 if (valueID == CSSValueBorder || valueID == CSSValueLines)
653 case CSSPropertyWebkitBoxAlign:
654 if (valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline)
657 case CSSPropertyWebkitBoxDecorationBreak:
658 if (valueID == CSSValueClone || valueID == CSSValueSlice)
661 case CSSPropertyWebkitBoxDirection:
662 if (valueID == CSSValueNormal || valueID == CSSValueReverse)
665 case CSSPropertyWebkitBoxLines:
666 if (valueID == CSSValueSingle || valueID == CSSValueMultiple)
669 case CSSPropertyWebkitBoxOrient:
670 if (valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis)
673 case CSSPropertyWebkitBoxPack:
674 if (valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify)
677 case CSSPropertyInternalCallback:
678 // This property is only injected programmatically, not parsed from stylesheets.
680 case CSSPropertyColumnFill:
681 if (RuntimeEnabledFeatures::regionBasedColumnsEnabled()) {
682 if (valueID == CSSValueAuto || valueID == CSSValueBalance)
686 case CSSPropertyAlignContent:
687 // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
688 if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch)
691 case CSSPropertyAlignItems:
692 // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
693 if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
696 case CSSPropertyAlignSelf:
697 // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
698 if (valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
701 case CSSPropertyFlexDirection:
702 if (valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse)
705 case CSSPropertyFlexWrap:
706 if (valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse)
709 case CSSPropertyJustifyContent:
710 // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
711 if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround)
714 case CSSPropertyFontKerning:
715 if (valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone)
718 case CSSPropertyWebkitFontSmoothing:
719 if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased)
722 case CSSPropertyGridAutoFlow:
723 if (valueID == CSSValueNone || valueID == CSSValueRow || valueID == CSSValueColumn)
724 return RuntimeEnabledFeatures::cssGridLayoutEnabled();
726 case CSSPropertyWebkitLineAlign:
727 if (valueID == CSSValueNone || valueID == CSSValueEdges)
730 case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
731 if (valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace)
734 case CSSPropertyWebkitLineSnap:
735 if (valueID == CSSValueNone || valueID == CSSValueBaseline || valueID == CSSValueContain)
738 case CSSPropertyWebkitMarginAfterCollapse:
739 case CSSPropertyWebkitMarginBeforeCollapse:
740 case CSSPropertyWebkitMarginBottomCollapse:
741 case CSSPropertyWebkitMarginTopCollapse:
742 if (valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard)
745 case CSSPropertyInternalMarqueeDirection:
746 if (valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
747 || valueID == CSSValueUp || valueID == CSSValueAuto)
750 case CSSPropertyInternalMarqueeStyle:
751 if (valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate)
754 case CSSPropertyWebkitPrintColorAdjust:
755 if (valueID == CSSValueExact || valueID == CSSValueEconomy)
758 case CSSPropertyWebkitRegionBreakAfter:
759 case CSSPropertyWebkitRegionBreakBefore:
760 if (RuntimeEnabledFeatures::cssRegionsEnabled() && (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight))
763 case CSSPropertyWebkitRegionBreakInside:
764 if (RuntimeEnabledFeatures::cssRegionsEnabled() && (valueID == CSSValueAuto || valueID == CSSValueAvoid))
767 case CSSPropertyWebkitRegionFragment:
768 if (RuntimeEnabledFeatures::cssRegionsEnabled() && (valueID == CSSValueAuto || valueID == CSSValueBreak))
771 case CSSPropertyWebkitRtlOrdering:
772 if (valueID == CSSValueLogical || valueID == CSSValueVisual)
776 case CSSPropertyWebkitRubyPosition:
777 if (valueID == CSSValueBefore || valueID == CSSValueAfter)
781 case CSSPropertyWebkitTextCombine:
782 if (valueID == CSSValueNone || valueID == CSSValueHorizontal)
785 case CSSPropertyWebkitTextEmphasisPosition:
786 if (valueID == CSSValueOver || valueID == CSSValueUnder)
789 case CSSPropertyWebkitTextSecurity:
790 // disc | circle | square | none | inherit
791 if (valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone)
794 case CSSPropertyWebkitTransformStyle:
795 if (valueID == CSSValueFlat || valueID == CSSValuePreserve3d)
798 case CSSPropertyWebkitUserDrag: // auto | none | element
799 if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement)
802 case CSSPropertyWebkitUserModify: // read-only | read-write
803 if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly)
806 case CSSPropertyWebkitUserSelect: // auto | none | text | all
807 if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll)
810 case CSSPropertyWebkitWrapFlow:
811 if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
813 if (valueID == CSSValueAuto || valueID == CSSValueBoth || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueMaximum || valueID == CSSValueClear)
816 case CSSPropertyWebkitWrapThrough:
817 if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
819 if (valueID == CSSValueWrap || valueID == CSSValueNone)
822 case CSSPropertyWebkitWritingMode:
823 if (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
826 case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit
827 if (valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap)
830 case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
831 if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord)
835 ASSERT_NOT_REACHED();
841 static inline bool isKeywordPropertyID(CSSPropertyID propertyId)
843 switch (propertyId) {
844 case CSSPropertyMixBlendMode:
845 case CSSPropertyIsolation:
846 case CSSPropertyBorderBottomStyle:
847 case CSSPropertyBorderCollapse:
848 case CSSPropertyBorderLeftStyle:
849 case CSSPropertyBorderRightStyle:
850 case CSSPropertyBorderTopStyle:
851 case CSSPropertyBoxSizing:
852 case CSSPropertyCaptionSide:
853 case CSSPropertyClear:
854 case CSSPropertyDirection:
855 case CSSPropertyDisplay:
856 case CSSPropertyEmptyCells:
857 case CSSPropertyFloat:
858 case CSSPropertyFontStyle:
859 case CSSPropertyImageRendering:
860 case CSSPropertyListStylePosition:
861 case CSSPropertyListStyleType:
862 case CSSPropertyObjectFit:
863 case CSSPropertyOutlineStyle:
864 case CSSPropertyOverflowWrap:
865 case CSSPropertyOverflowX:
866 case CSSPropertyOverflowY:
867 case CSSPropertyPageBreakAfter:
868 case CSSPropertyPageBreakBefore:
869 case CSSPropertyPageBreakInside:
870 case CSSPropertyPointerEvents:
871 case CSSPropertyPosition:
872 case CSSPropertyResize:
873 case CSSPropertyScrollBehavior:
874 case CSSPropertySpeak:
875 case CSSPropertyTableLayout:
876 case CSSPropertyTextAlignLast:
877 case CSSPropertyTextJustify:
878 case CSSPropertyTextLineThroughMode:
879 case CSSPropertyTextLineThroughStyle:
880 case CSSPropertyTextOverflow:
881 case CSSPropertyTextOverlineMode:
882 case CSSPropertyTextOverlineStyle:
883 case CSSPropertyTextRendering:
884 case CSSPropertyTextTransform:
885 case CSSPropertyTextUnderlineMode:
886 case CSSPropertyTextUnderlineStyle:
887 case CSSPropertyTouchActionDelay:
888 case CSSPropertyVisibility:
889 case CSSPropertyWebkitAppearance:
890 case CSSPropertyWebkitBackfaceVisibility:
891 case CSSPropertyWebkitBorderAfterStyle:
892 case CSSPropertyWebkitBorderBeforeStyle:
893 case CSSPropertyWebkitBorderEndStyle:
894 case CSSPropertyWebkitBorderFit:
895 case CSSPropertyWebkitBorderStartStyle:
896 case CSSPropertyWebkitBoxAlign:
897 case CSSPropertyWebkitBoxDecorationBreak:
898 case CSSPropertyWebkitBoxDirection:
899 case CSSPropertyWebkitBoxLines:
900 case CSSPropertyWebkitBoxOrient:
901 case CSSPropertyWebkitBoxPack:
902 case CSSPropertyInternalCallback:
903 case CSSPropertyWebkitColumnBreakAfter:
904 case CSSPropertyWebkitColumnBreakBefore:
905 case CSSPropertyWebkitColumnBreakInside:
906 case CSSPropertyColumnFill:
907 case CSSPropertyWebkitColumnRuleStyle:
908 case CSSPropertyAlignContent:
909 case CSSPropertyFlexDirection:
910 case CSSPropertyFlexWrap:
911 case CSSPropertyJustifyContent:
912 case CSSPropertyFontKerning:
913 case CSSPropertyWebkitFontSmoothing:
914 case CSSPropertyGridAutoFlow:
915 case CSSPropertyWebkitLineAlign:
916 case CSSPropertyWebkitLineBreak:
917 case CSSPropertyWebkitLineSnap:
918 case CSSPropertyWebkitMarginAfterCollapse:
919 case CSSPropertyWebkitMarginBeforeCollapse:
920 case CSSPropertyWebkitMarginBottomCollapse:
921 case CSSPropertyWebkitMarginTopCollapse:
922 case CSSPropertyInternalMarqueeDirection:
923 case CSSPropertyInternalMarqueeStyle:
924 case CSSPropertyWebkitPrintColorAdjust:
925 case CSSPropertyWebkitRegionBreakAfter:
926 case CSSPropertyWebkitRegionBreakBefore:
927 case CSSPropertyWebkitRegionBreakInside:
928 case CSSPropertyWebkitRegionFragment:
929 case CSSPropertyWebkitRtlOrdering:
930 case CSSPropertyWebkitRubyPosition:
931 case CSSPropertyWebkitTextCombine:
932 case CSSPropertyWebkitTextEmphasisPosition:
933 case CSSPropertyWebkitTextSecurity:
934 case CSSPropertyWebkitTransformStyle:
935 case CSSPropertyWebkitUserDrag:
936 case CSSPropertyWebkitUserModify:
937 case CSSPropertyWebkitUserSelect:
938 case CSSPropertyWebkitWrapFlow:
939 case CSSPropertyWebkitWrapThrough:
940 case CSSPropertyWebkitWritingMode:
941 case CSSPropertyWhiteSpace:
942 case CSSPropertyWordBreak:
943 case CSSPropertyWordWrap:
945 case CSSPropertyAlignItems:
946 case CSSPropertyAlignSelf:
947 return !RuntimeEnabledFeatures::cssGridLayoutEnabled();
953 static bool parseKeywordValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext)
955 ASSERT(!string.isEmpty());
957 if (!isKeywordPropertyID(propertyId)) {
958 // All properties accept the values of "initial" and "inherit".
959 String lowerCaseString = string.lower();
960 if (lowerCaseString != "initial" && lowerCaseString != "inherit")
963 // Parse initial/inherit shorthands using the BisonCSSParser.
964 if (shorthandForProperty(propertyId).length())
968 CSSParserString cssString;
969 cssString.init(string);
970 CSSValueID valueID = cssValueKeywordID(cssString);
975 RefPtr<CSSValue> value;
976 if (valueID == CSSValueInherit)
977 value = cssValuePool().createInheritedValue();
978 else if (valueID == CSSValueInitial)
979 value = cssValuePool().createExplicitInitialValue();
980 else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext))
981 value = cssValuePool().createIdentifierValue(valueID);
985 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
989 template <typename CharType>
990 static bool parseTransformTranslateArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSTransformValue* transformValue)
992 while (expectedCount) {
993 size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
994 if (delimiter == kNotFound)
996 unsigned argumentLength = static_cast<unsigned>(delimiter);
997 CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
999 if (!parseSimpleLength(pos, argumentLength, unit, number))
1001 if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER))
1003 transformValue->append(cssValuePool().createValue(number, CSSPrimitiveValue::CSS_PX));
1004 pos += argumentLength + 1;
1010 template <typename CharType>
1011 static PassRefPtr<CSSTransformValue> parseTranslateTransformValue(CharType*& pos, CharType* end)
1013 static const int shortestValidTransformStringLength = 12;
1015 if (end - pos < shortestValidTransformStringLength)
1018 if ((pos[0] != 't' && pos[0] != 'T')
1019 || (pos[1] != 'r' && pos[1] != 'R')
1020 || (pos[2] != 'a' && pos[2] != 'A')
1021 || (pos[3] != 'n' && pos[3] != 'N')
1022 || (pos[4] != 's' && pos[4] != 'S')
1023 || (pos[5] != 'l' && pos[5] != 'L')
1024 || (pos[6] != 'a' && pos[6] != 'A')
1025 || (pos[7] != 't' && pos[7] != 'T')
1026 || (pos[8] != 'e' && pos[8] != 'E'))
1029 CSSTransformValue::TransformOperationType transformType;
1030 unsigned expectedArgumentCount = 1;
1031 unsigned argumentStart = 11;
1032 if ((pos[9] == 'x' || pos[9] == 'X') && pos[10] == '(') {
1033 transformType = CSSTransformValue::TranslateXTransformOperation;
1034 } else if ((pos[9] == 'y' || pos[9] == 'Y') && pos[10] == '(') {
1035 transformType = CSSTransformValue::TranslateYTransformOperation;
1036 } else if ((pos[9] == 'z' || pos[9] == 'Z') && pos[10] == '(') {
1037 transformType = CSSTransformValue::TranslateZTransformOperation;
1038 } else if (pos[9] == '(') {
1039 transformType = CSSTransformValue::TranslateTransformOperation;
1040 expectedArgumentCount = 2;
1042 } else if (pos[9] == '3' && (pos[10] == 'd' || pos[10] == 'D') && pos[11] == '(') {
1043 transformType = CSSTransformValue::Translate3DTransformOperation;
1044 expectedArgumentCount = 3;
1049 pos += argumentStart;
1051 RefPtr<CSSTransformValue> transformValue = CSSTransformValue::create(transformType);
1052 if (!parseTransformTranslateArguments(pos, end, expectedArgumentCount, transformValue.get()))
1054 return transformValue.release();
1057 template <typename CharType>
1058 static PassRefPtr<CSSValueList> parseTranslateTransformList(CharType*& pos, CharType* end)
1060 RefPtr<CSSValueList> transformList;
1062 while (pos < end && isCSSSpace(*pos))
1064 RefPtr<CSSTransformValue> transformValue = parseTranslateTransformValue(pos, end);
1065 if (!transformValue)
1068 transformList = CSSValueList::createSpaceSeparated();
1069 transformList->append(transformValue.release());
1071 if (isCSSSpace(*pos))
1075 return transformList.release();
1078 static bool parseTranslateTransform(MutableStylePropertySet* properties, CSSPropertyID propertyID, const String& string, bool important)
1080 if (propertyID != CSSPropertyWebkitTransform)
1082 if (string.isEmpty())
1084 RefPtr<CSSValueList> transformList;
1085 if (string.is8Bit()) {
1086 const LChar* pos = string.characters8();
1087 const LChar* end = pos + string.length();
1088 transformList = parseTranslateTransformList(pos, end);
1092 const UChar* pos = string.characters16();
1093 const UChar* end = pos + string.length();
1094 transformList = parseTranslateTransformList(pos, end);
1098 properties->addParsedProperty(CSSProperty(CSSPropertyWebkitTransform, transformList.release(), important));
1102 PassRefPtr<CSSValueList> BisonCSSParser::parseFontFaceValue(const AtomicString& string)
1104 if (string.isEmpty())
1106 RefPtr<MutableStylePropertySet> dummyStyle = MutableStylePropertySet::create();
1107 if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, HTMLQuirksMode, 0))
1110 RefPtr<CSSValue> fontFamily = dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily);
1111 if (!fontFamily->isValueList())
1114 return toCSSValueList(dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily).get());
1117 bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, const Document& document)
1119 ASSERT(!string.isEmpty());
1121 CSSParserContext context(document);
1123 if (parseSimpleLengthValue(declaration, propertyID, string, important, context.mode()))
1125 if (parseColorValue(declaration, propertyID, string, important, context.mode()))
1127 if (parseKeywordValue(declaration, propertyID, string, important, context))
1130 BisonCSSParser parser(context, UseCounter::getFrom(&document));
1131 return parser.parseValue(declaration, propertyID, string, important, static_cast<StyleSheetContents*>(0));
1134 bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
1136 ASSERT(!string.isEmpty());
1137 if (parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode))
1139 if (parseColorValue(declaration, propertyID, string, important, cssParserMode))
1142 CSSParserContext context(cssParserMode);
1143 if (contextStyleSheet) {
1144 context = contextStyleSheet->parserContext();
1145 context.setMode(cssParserMode);
1148 if (parseKeywordValue(declaration, propertyID, string, important, context))
1150 if (parseTranslateTransform(declaration, propertyID, string, important))
1153 BisonCSSParser parser(context);
1154 return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet);
1157 bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet)
1159 // FIXME: Check RuntimeCSSEnabled::isPropertyEnabled or isValueEnabledForProperty.
1162 m_useCounter->count(m_context, propertyID);
1164 setStyleSheet(contextStyleSheet);
1166 setupParser("@-internal-value ", string, "");
1169 m_important = important;
1172 StyleDeclarationScope scope(this, declaration);
1177 m_id = CSSPropertyInvalid;
1180 if (m_hasFontFaceOnlyValues)
1181 deleteFontFaceOnlyValues();
1182 if (!m_parsedProperties.isEmpty()) {
1184 declaration->addParsedProperties(m_parsedProperties);
1191 // The color will only be changed when string contains a valid CSS color, so callers
1192 // can set it to a default color and ignore the boolean result.
1193 bool BisonCSSParser::parseColor(RGBA32& color, const String& string, bool strict)
1195 // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
1196 if (fastParseColor(color, string, strict))
1199 BisonCSSParser parser(HTMLStandardMode);
1201 // In case the fast-path parser didn't understand the color, try the full parser.
1202 if (!parser.parseColor(string))
1205 CSSValue* value = parser.m_parsedProperties.first().value();
1206 if (!value->isPrimitiveValue())
1209 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
1210 if (!primitiveValue->isRGBColor())
1213 color = primitiveValue->getRGBA32Value();
1217 bool BisonCSSParser::parseColor(const String& string)
1219 setupParser("@-internal-decls color:", string, "");
1223 return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor;
1226 // FIXME: This is copied from SVGCSSParser.cpp
1227 static bool isSystemColor(int id)
1229 return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu;
1232 bool BisonCSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document)
1237 CSSParserString cssColor;
1238 cssColor.init(string);
1239 CSSValueID id = cssValueKeywordID(cssColor);
1240 if (!isSystemColor(id))
1243 Color parsedColor = RenderTheme::theme().systemColor(id);
1244 color = parsedColor.rgb();
1248 void BisonCSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
1250 m_selectorListForParseSelector = &selectorList;
1252 setupParser("@-internal-selector ", string, "");
1256 m_selectorListForParseSelector = 0;
1259 PassRefPtr<ImmutableStylePropertySet> BisonCSSParser::parseInlineStyleDeclaration(const String& string, Element* element)
1261 Document& document = element->document();
1262 CSSParserContext context = document.elementSheet()->contents()->parserContext();
1263 context.setMode((element->isHTMLElement() && !document.inQuirksMode()) ? HTMLStandardMode : HTMLQuirksMode);
1264 return BisonCSSParser(context, UseCounter::getFrom(&document)).parseDeclaration(string, document.elementSheet()->contents());
1267 PassRefPtr<ImmutableStylePropertySet> BisonCSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet)
1269 setStyleSheet(contextStyleSheet);
1271 setupParser("@-internal-decls ", string, "");
1275 if (m_hasFontFaceOnlyValues)
1276 deleteFontFaceOnlyValues();
1278 RefPtr<ImmutableStylePropertySet> style = createStylePropertySet();
1280 return style.release();
1284 bool BisonCSSParser::parseDeclaration(MutableStylePropertySet* declaration, const String& string, CSSParserObserver* observer, StyleSheetContents* contextStyleSheet)
1286 setStyleSheet(contextStyleSheet);
1288 TemporaryChange<CSSParserObserver*> scopedObsever(m_observer, observer);
1290 setupParser("@-internal-decls ", string, "");
1292 m_observer->startRuleHeader(CSSRuleSourceData::STYLE_RULE, 0);
1293 m_observer->endRuleHeader(1);
1294 m_observer->startRuleBody(0);
1298 StyleDeclarationScope scope(this, declaration);
1305 if (m_hasFontFaceOnlyValues)
1306 deleteFontFaceOnlyValues();
1307 if (!m_parsedProperties.isEmpty()) {
1309 declaration->addParsedProperties(m_parsedProperties);
1314 m_observer->endRuleBody(string.length(), false);
1319 PassRefPtr<MediaQuerySet> BisonCSSParser::parseMediaQueryList(const String& string)
1321 ASSERT(!m_mediaList);
1323 // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
1324 // instead insert one " " (which is caught by maybe_space in CSSGrammar.y)
1325 setupParser("@-internal-medialist ", string, "");
1328 ASSERT(m_mediaList);
1329 return m_mediaList.release();
1332 static inline void filterProperties(bool important, const BisonCSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties, HashSet<AtomicString>& seenVariables)
1334 // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
1335 for (int i = input.size() - 1; i >= 0; --i) {
1336 const CSSProperty& property = input[i];
1337 if (property.isImportant() != important)
1339 if (property.id() == CSSPropertyVariable) {
1340 const AtomicString& name = toCSSVariableValue(property.value())->name();
1341 if (!seenVariables.add(name).isNewEntry)
1343 output[--unusedEntries] = property;
1346 const unsigned propertyIDIndex = property.id() - firstCSSProperty;
1347 if (seenProperties.get(propertyIDIndex))
1349 seenProperties.set(propertyIDIndex);
1350 output[--unusedEntries] = property;
1354 PassRefPtr<ImmutableStylePropertySet> BisonCSSParser::createStylePropertySet()
1356 BitArray<numCSSProperties> seenProperties;
1357 size_t unusedEntries = m_parsedProperties.size();
1358 Vector<CSSProperty, 256> results(unusedEntries);
1360 // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found.
1361 HashSet<AtomicString> seenVariables;
1362 filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
1363 filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
1365 results.remove(0, unusedEntries);
1367 CSSParserMode mode = inViewport() ? CSSViewportRuleMode : m_context.mode();
1369 return ImmutableStylePropertySet::create(results.data(), results.size(), mode);
1372 void BisonCSSParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
1374 RefPtr<CSSValue> val = value.get();
1375 addProperty(propId, value, important, implicit);
1377 CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId);
1378 if (prefixingVariant == propId)
1381 if (m_currentShorthand) {
1382 // We can't use ShorthandScope here as we can already be inside one (e.g we are parsing CSSTransition).
1383 m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
1384 addProperty(prefixingVariant, val.release(), important, implicit);
1385 m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
1387 addProperty(prefixingVariant, val.release(), important, implicit);
1391 void BisonCSSParser::addProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
1393 CSSPrimitiveValue* primitiveValue = value->isPrimitiveValue() ? toCSSPrimitiveValue(value.get()) : 0;
1394 // This property doesn't belong to a shorthand or is a CSS variable (which will be resolved later).
1395 if (!m_currentShorthand || (primitiveValue && primitiveValue->isVariableReference())) {
1396 m_parsedProperties.append(CSSProperty(propId, value, important, false, CSSPropertyInvalid, m_implicitShorthand || implicit));
1400 Vector<StylePropertyShorthand, 4> shorthands;
1401 getMatchingShorthandsForLonghand(propId, &shorthands);
1402 // The longhand does not belong to multiple shorthands.
1403 if (shorthands.size() == 1)
1404 m_parsedProperties.append(CSSProperty(propId, value, important, true, CSSPropertyInvalid, m_implicitShorthand || implicit));
1406 m_parsedProperties.append(CSSProperty(propId, value, important, true, indexOfShorthandForLonghand(m_currentShorthand, shorthands), m_implicitShorthand || implicit));
1409 void BisonCSSParser::rollbackLastProperties(int num)
1412 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
1413 m_parsedProperties.shrink(m_parsedProperties.size() - num);
1416 void BisonCSSParser::clearProperties()
1418 m_parsedProperties.clear();
1419 m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
1420 m_hasFontFaceOnlyValues = false;
1423 KURL BisonCSSParser::completeURL(const String& url) const
1425 return m_context.completeURL(url);
1428 bool BisonCSSParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc)
1430 bool mustBeNonNegative = unitflags & FNonNeg;
1432 if (!parseCalculation(value, mustBeNonNegative ? ValueRangeNonNegative : ValueRangeAll))
1436 switch (m_parsedCalculation->category()) {
1438 b = (unitflags & FLength);
1441 b = (unitflags & FPercent);
1442 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1446 b = (unitflags & FNumber);
1447 if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
1449 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1452 case CalcPercentLength:
1453 b = (unitflags & FPercent) && (unitflags & FLength);
1455 case CalcPercentNumber:
1456 b = (unitflags & FPercent) && (unitflags & FNumber);
1464 if (!b || releaseCalc == ReleaseParsedCalcValue)
1465 m_parsedCalculation.release();
1469 static bool isVariableReference(CSSParserValue* value)
1471 return value->unit == CSSParserValue::Function && equal(value->function->name, "var(");
1474 inline bool BisonCSSParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
1476 // Quirks mode and presentation attributes accept unit less values.
1477 return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || isUnitLessLengthParsingEnabledForMode(cssParserMode));
1480 bool BisonCSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
1482 if (isCalculation(value))
1483 return validCalculationUnit(value, unitflags, releaseCalc);
1485 // Variables are checked at the point they are dereferenced because unit type is not available here.
1486 if (isVariableReference(value))
1490 switch (value->unit) {
1491 case CSSPrimitiveValue::CSS_NUMBER:
1492 b = (unitflags & FNumber);
1493 if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
1494 value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
1495 ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
1498 if (!b && (unitflags & FInteger) && value->isInt)
1500 if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0)
1503 case CSSPrimitiveValue::CSS_PERCENTAGE:
1504 b = (unitflags & FPercent);
1506 case CSSParserValue::Q_EMS:
1507 case CSSPrimitiveValue::CSS_EMS:
1508 case CSSPrimitiveValue::CSS_REMS:
1509 case CSSPrimitiveValue::CSS_CHS:
1510 case CSSPrimitiveValue::CSS_EXS:
1511 case CSSPrimitiveValue::CSS_PX:
1512 case CSSPrimitiveValue::CSS_CM:
1513 case CSSPrimitiveValue::CSS_MM:
1514 case CSSPrimitiveValue::CSS_IN:
1515 case CSSPrimitiveValue::CSS_PT:
1516 case CSSPrimitiveValue::CSS_PC:
1517 case CSSPrimitiveValue::CSS_VW:
1518 case CSSPrimitiveValue::CSS_VH:
1519 case CSSPrimitiveValue::CSS_VMIN:
1520 case CSSPrimitiveValue::CSS_VMAX:
1521 b = (unitflags & FLength);
1523 case CSSPrimitiveValue::CSS_MS:
1524 case CSSPrimitiveValue::CSS_S:
1525 b = (unitflags & FTime);
1527 case CSSPrimitiveValue::CSS_DEG:
1528 case CSSPrimitiveValue::CSS_RAD:
1529 case CSSPrimitiveValue::CSS_GRAD:
1530 case CSSPrimitiveValue::CSS_TURN:
1531 b = (unitflags & FAngle);
1533 case CSSPrimitiveValue::CSS_DPPX:
1534 case CSSPrimitiveValue::CSS_DPI:
1535 case CSSPrimitiveValue::CSS_DPCM:
1536 b = (unitflags & FResolution);
1538 case CSSPrimitiveValue::CSS_HZ:
1539 case CSSPrimitiveValue::CSS_KHZ:
1540 case CSSPrimitiveValue::CSS_DIMENSION:
1544 if (b && unitflags & FNonNeg && value->fValue < 0)
1549 inline PassRefPtr<CSSPrimitiveValue> BisonCSSParser::createPrimitiveNumericValue(CSSParserValue* value)
1551 if (isVariableReference(value))
1552 return createPrimitiveVariableReferenceValue(value);
1554 if (m_parsedCalculation) {
1555 ASSERT(isCalculation(value));
1556 return CSSPrimitiveValue::create(m_parsedCalculation.release());
1559 ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1560 || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
1561 || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
1562 || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
1563 return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
1566 inline PassRefPtr<CSSPrimitiveValue> BisonCSSParser::createPrimitiveStringValue(CSSParserValue* value)
1568 ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
1569 return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
1572 inline PassRefPtr<CSSPrimitiveValue> BisonCSSParser::createPrimitiveVariableReferenceValue(CSSParserValue* value)
1574 ASSERT(value->unit == CSSParserValue::Function && value->function->args->size() == 1);
1575 return CSSPrimitiveValue::create(value->function->args->valueAt(0)->string, CSSPrimitiveValue::CSS_VARIABLE_REFERENCE);
1578 static inline bool isComma(CSSParserValue* value)
1580 return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
1583 static inline bool isForwardSlashOperator(CSSParserValue* value)
1586 return value->unit == CSSParserValue::Operator && value->iValue == '/';
1589 static bool isGeneratedImageValue(CSSParserValue* val)
1591 if (val->unit != CSSParserValue::Function)
1594 return equalIgnoringCase(val->function->name, "-webkit-gradient(")
1595 || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
1596 || equalIgnoringCase(val->function->name, "linear-gradient(")
1597 || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
1598 || equalIgnoringCase(val->function->name, "repeating-linear-gradient(")
1599 || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
1600 || equalIgnoringCase(val->function->name, "radial-gradient(")
1601 || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
1602 || equalIgnoringCase(val->function->name, "repeating-radial-gradient(")
1603 || equalIgnoringCase(val->function->name, "-webkit-canvas(")
1604 || equalIgnoringCase(val->function->name, "-webkit-cross-fade(");
1607 bool BisonCSSParser::validWidthOrHeight(CSSParserValue* value)
1610 if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
1612 return !id && validUnit(value, FLength | FPercent | FNonNeg);
1615 inline PassRefPtr<CSSPrimitiveValue> BisonCSSParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value)
1618 return cssValuePool().createIdentifierValue(identifier);
1619 if (value->unit == CSSPrimitiveValue::CSS_STRING)
1620 return createPrimitiveStringValue(value);
1621 if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1622 return createPrimitiveNumericValue(value);
1623 if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
1624 return createPrimitiveNumericValue(value);
1625 if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
1626 return createPrimitiveNumericValue(value);
1627 if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
1628 return createPrimitiveNumericValue(value);
1629 if (value->unit >= CSSParserValue::Q_EMS)
1630 return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
1631 if (isCalculation(value))
1632 return CSSPrimitiveValue::create(m_parsedCalculation.release());
1633 if (isVariableReference(value))
1634 return createPrimitiveVariableReferenceValue(value);
1639 void BisonCSSParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtr<CSSValue> prpValue, bool important)
1641 const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
1642 unsigned shorthandLength = shorthand.length();
1643 if (!shorthandLength) {
1644 addProperty(propId, prpValue, important);
1648 RefPtr<CSSValue> value = prpValue;
1649 ShorthandScope scope(this, propId);
1650 const CSSPropertyID* longhands = shorthand.properties();
1651 for (unsigned i = 0; i < shorthandLength; ++i)
1652 addProperty(longhands[i], value, important);
1655 void BisonCSSParser::setCurrentProperty(CSSPropertyID propId)
1660 bool BisonCSSParser::parseValue(CSSPropertyID propId, bool important)
1662 if (!isInternalPropertyAndValueParsingEnabledForMode(m_context.mode()) && isInternalProperty(propId))
1665 // We don't count the UA style sheet in our statistics.
1667 m_useCounter->count(m_context, propId);
1672 CSSParserValue* value = m_valueList->current();
1678 // Allow @viewport rules from UA stylesheets even if the feature is disabled.
1679 if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode()))
1682 return parseViewportProperty(propId, important);
1685 // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
1686 // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
1687 ASSERT(!m_parsedCalculation);
1689 CSSValueID id = value->id;
1691 int num = inShorthand() ? 1 : m_valueList->size();
1693 if (id == CSSValueInherit) {
1696 addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important);
1699 else if (id == CSSValueInitial) {
1702 addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important);
1706 if (!id && num == 1 && isVariableReference(value)) {
1707 addProperty(propId, createPrimitiveVariableReferenceValue(value), important);
1708 m_valueList->next();
1711 ASSERT(propId != CSSPropertyVariable);
1713 if (isKeywordPropertyID(propId)) {
1714 if (!isValidKeywordPropertyAndValue(propId, id, m_context))
1716 if (m_valueList->next() && !inShorthand())
1718 addProperty(propId, cssValuePool().createIdentifierValue(id), important);
1722 bool validPrimitive = false;
1723 RefPtr<CSSValue> parsedValue;
1726 case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
1727 return parseSize(propId, important);
1729 case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit
1731 validPrimitive = true;
1733 return parseQuotes(propId, important);
1735 case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | isolate-override | plaintext | inherit
1736 if (id == CSSValueNormal
1737 || id == CSSValueEmbed
1738 || id == CSSValueBidiOverride
1739 || id == CSSValueWebkitIsolate
1740 || id == CSSValueWebkitIsolateOverride
1741 || id == CSSValueWebkitPlaintext)
1742 validPrimitive = true;
1745 case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
1746 // close-quote | no-open-quote | no-close-quote ]+ | inherit
1747 return parseContent(propId, important);
1749 case CSSPropertyClip: // <shape> | auto | inherit
1750 if (id == CSSValueAuto)
1751 validPrimitive = true;
1752 else if (value->unit == CSSParserValue::Function)
1753 return parseClipShape(propId, important);
1756 /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
1757 * correctly and allows optimization in WebCore::applyRule(..)
1759 case CSSPropertyOverflow: {
1760 ShorthandScope scope(this, propId);
1761 if (num != 1 || !parseValue(CSSPropertyOverflowY, important))
1764 RefPtr<CSSValue> overflowXValue;
1766 // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been
1767 // set using the shorthand, then for now overflow-x will default to auto, but once we implement
1768 // pagination controls, it should default to hidden. If the overflow-y value is anything but
1769 // paged-x or paged-y, then overflow-x and overflow-y should have the same value.
1770 if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
1771 overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
1773 overflowXValue = m_parsedProperties.last().value();
1774 addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
1778 case CSSPropertyTextAlign:
1779 // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
1780 // | start | end | <string> | inherit | -webkit-auto (converted to start)
1781 if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
1782 || value->unit == CSSPrimitiveValue::CSS_STRING)
1783 validPrimitive = true;
1786 case CSSPropertyFontWeight: { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
1787 if (m_valueList->size() != 1)
1789 return parseFontWeight(important);
1791 case CSSPropertyBorderSpacing: {
1793 ShorthandScope scope(this, CSSPropertyBorderSpacing);
1794 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
1796 CSSValue* value = m_parsedProperties.last().value();
1797 addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
1800 else if (num == 2) {
1801 ShorthandScope scope(this, CSSPropertyBorderSpacing);
1802 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
1808 case CSSPropertyWebkitBorderHorizontalSpacing:
1809 case CSSPropertyWebkitBorderVerticalSpacing:
1810 validPrimitive = validUnit(value, FLength | FNonNeg);
1812 case CSSPropertyOutlineColor: // <color> | invert | inherit
1813 // Outline color has "invert" as additional keyword.
1814 // Also, we want to allow the special focus color even in HTML Standard parsing mode.
1815 if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
1816 validPrimitive = true;
1820 case CSSPropertyBackgroundColor: // <color> | inherit
1821 case CSSPropertyBorderTopColor: // <color> | inherit
1822 case CSSPropertyBorderRightColor:
1823 case CSSPropertyBorderBottomColor:
1824 case CSSPropertyBorderLeftColor:
1825 case CSSPropertyWebkitBorderStartColor:
1826 case CSSPropertyWebkitBorderEndColor:
1827 case CSSPropertyWebkitBorderBeforeColor:
1828 case CSSPropertyWebkitBorderAfterColor:
1829 case CSSPropertyColor: // <color> | inherit
1830 case CSSPropertyTextDecorationColor: // CSS3 text decoration colors
1831 case CSSPropertyTextLineThroughColor:
1832 case CSSPropertyTextUnderlineColor:
1833 case CSSPropertyTextOverlineColor:
1834 case CSSPropertyWebkitColumnRuleColor:
1835 case CSSPropertyWebkitTextEmphasisColor:
1836 case CSSPropertyWebkitTextFillColor:
1837 case CSSPropertyWebkitTextStrokeColor:
1838 if (propId == CSSPropertyTextDecorationColor
1839 && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
1842 if ((id >= CSSValueAqua && id <= CSSValueWebkitText) || id == CSSValueMenu) {
1843 validPrimitive = isValueAllowedInMode(id, m_context.mode());
1845 parsedValue = parseColor();
1847 m_valueList->next();
1851 case CSSPropertyCursor: {
1852 // Grammar defined by CSS3 UI and modified by CSS4 images:
1853 // [ [<image> [<x> <y>]?,]*
1854 // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
1855 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
1856 // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
1857 // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
1858 // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
1859 RefPtr<CSSValueList> list;
1861 RefPtr<CSSValue> image = 0;
1862 if (value->unit == CSSPrimitiveValue::CSS_URI) {
1863 String uri = value->string;
1865 image = CSSImageValue::create(completeURL(uri));
1866 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
1867 image = parseImageSet(m_valueList.get());
1874 value = m_valueList->next();
1875 while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
1876 coords.append(int(value->fValue));
1877 value = m_valueList->next();
1879 bool hasHotSpot = false;
1880 IntPoint hotSpot(-1, -1);
1881 int nrcoords = coords.size();
1882 if (nrcoords > 0 && nrcoords != 2)
1884 if (nrcoords == 2) {
1886 hotSpot = IntPoint(coords[0], coords[1]);
1890 list = CSSValueList::createCommaSeparated();
1893 list->append(CSSCursorImageValue::create(image, hasHotSpot, hotSpot));
1895 if (!value || !(value->unit == CSSParserValue::Operator && value->iValue == ','))
1897 value = m_valueList->next(); // comma
1902 if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
1903 list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
1904 else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
1905 list->append(cssValuePool().createIdentifierValue(value->id));
1906 m_valueList->next();
1907 parsedValue = list.release();
1911 if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
1912 id = CSSValuePointer;
1913 validPrimitive = true;
1914 } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
1915 validPrimitive = true;
1917 ASSERT_NOT_REACHED();
1923 case CSSPropertyBackgroundBlendMode:
1924 case CSSPropertyBackgroundAttachment:
1925 case CSSPropertyBackgroundClip:
1926 case CSSPropertyWebkitBackgroundClip:
1927 case CSSPropertyWebkitBackgroundComposite:
1928 case CSSPropertyBackgroundImage:
1929 case CSSPropertyBackgroundOrigin:
1930 case CSSPropertyMaskSourceType:
1931 case CSSPropertyWebkitBackgroundOrigin:
1932 case CSSPropertyBackgroundPosition:
1933 case CSSPropertyBackgroundPositionX:
1934 case CSSPropertyBackgroundPositionY:
1935 case CSSPropertyBackgroundSize:
1936 case CSSPropertyWebkitBackgroundSize:
1937 case CSSPropertyBackgroundRepeat:
1938 case CSSPropertyBackgroundRepeatX:
1939 case CSSPropertyBackgroundRepeatY:
1940 case CSSPropertyWebkitMaskClip:
1941 case CSSPropertyWebkitMaskComposite:
1942 case CSSPropertyWebkitMaskImage:
1943 case CSSPropertyWebkitMaskOrigin:
1944 case CSSPropertyWebkitMaskPosition:
1945 case CSSPropertyWebkitMaskPositionX:
1946 case CSSPropertyWebkitMaskPositionY:
1947 case CSSPropertyWebkitMaskSize:
1948 case CSSPropertyWebkitMaskRepeat:
1949 case CSSPropertyWebkitMaskRepeatX:
1950 case CSSPropertyWebkitMaskRepeatY:
1952 RefPtr<CSSValue> val1;
1953 RefPtr<CSSValue> val2;
1954 CSSPropertyID propId1, propId2;
1955 bool result = false;
1956 if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
1957 OwnPtr<ShorthandScope> shorthandScope;
1958 if (propId == CSSPropertyBackgroundPosition ||
1959 propId == CSSPropertyBackgroundRepeat ||
1960 propId == CSSPropertyWebkitMaskPosition ||
1961 propId == CSSPropertyWebkitMaskRepeat) {
1962 shorthandScope = adoptPtr(new ShorthandScope(this, propId));
1964 addProperty(propId1, val1.release(), important);
1966 addProperty(propId2, val2.release(), important);
1969 m_implicitShorthand = false;
1972 case CSSPropertyObjectPosition:
1973 return RuntimeEnabledFeatures::objectFitPositionEnabled() && parseObjectPosition(important);
1974 case CSSPropertyListStyleImage: // <uri> | none | inherit
1975 case CSSPropertyBorderImageSource:
1976 case CSSPropertyWebkitMaskBoxImageSource:
1977 if (id == CSSValueNone) {
1978 parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
1979 m_valueList->next();
1980 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
1981 parsedValue = CSSImageValue::create(completeURL(value->string));
1982 m_valueList->next();
1983 } else if (isGeneratedImageValue(value)) {
1984 if (parseGeneratedImage(m_valueList.get(), parsedValue))
1985 m_valueList->next();
1989 else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
1990 parsedValue = parseImageSet(m_valueList.get());
1993 m_valueList->next();
1997 case CSSPropertyWebkitTextStrokeWidth:
1998 case CSSPropertyOutlineWidth: // <border-width> | inherit
1999 case CSSPropertyBorderTopWidth: //// <border-width> | inherit
2000 case CSSPropertyBorderRightWidth: // Which is defined as
2001 case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
2002 case CSSPropertyBorderLeftWidth:
2003 case CSSPropertyWebkitBorderStartWidth:
2004 case CSSPropertyWebkitBorderEndWidth:
2005 case CSSPropertyWebkitBorderBeforeWidth:
2006 case CSSPropertyWebkitBorderAfterWidth:
2007 case CSSPropertyWebkitColumnRuleWidth:
2008 if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
2009 validPrimitive = true;
2011 validPrimitive = validUnit(value, FLength | FNonNeg);
2014 case CSSPropertyLetterSpacing: // normal | <length> | inherit
2015 case CSSPropertyWordSpacing: // normal | <length> | inherit
2016 if (id == CSSValueNormal)
2017 validPrimitive = true;
2019 validPrimitive = validUnit(value, FLength);
2022 case CSSPropertyTextIndent:
2023 parsedValue = parseTextIndent();
2026 case CSSPropertyPaddingTop: //// <padding-width> | inherit
2027 case CSSPropertyPaddingRight: // Which is defined as
2028 case CSSPropertyPaddingBottom: // <length> | <percentage>
2029 case CSSPropertyPaddingLeft: ////
2030 case CSSPropertyWebkitPaddingStart:
2031 case CSSPropertyWebkitPaddingEnd:
2032 case CSSPropertyWebkitPaddingBefore:
2033 case CSSPropertyWebkitPaddingAfter:
2034 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
2037 case CSSPropertyMaxWidth:
2038 case CSSPropertyWebkitMaxLogicalWidth:
2039 case CSSPropertyMaxHeight:
2040 case CSSPropertyWebkitMaxLogicalHeight:
2041 validPrimitive = (id == CSSValueNone || validWidthOrHeight(value));
2044 case CSSPropertyMinWidth:
2045 case CSSPropertyWebkitMinLogicalWidth:
2046 case CSSPropertyMinHeight:
2047 case CSSPropertyWebkitMinLogicalHeight:
2048 validPrimitive = validWidthOrHeight(value);
2051 case CSSPropertyWidth:
2052 case CSSPropertyWebkitLogicalWidth:
2053 case CSSPropertyHeight:
2054 case CSSPropertyWebkitLogicalHeight:
2055 validPrimitive = (id == CSSValueAuto || validWidthOrHeight(value));
2058 case CSSPropertyFontSize:
2059 return parseFontSize(important);
2061 case CSSPropertyFontVariant: // normal | small-caps | inherit
2062 return parseFontVariant(important);
2064 case CSSPropertyVerticalAlign:
2065 // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
2066 // <percentage> | <length> | inherit
2068 if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
2069 validPrimitive = true;
2071 validPrimitive = (!id && validUnit(value, FLength | FPercent));
2074 case CSSPropertyBottom: // <length> | <percentage> | auto | inherit
2075 case CSSPropertyLeft: // <length> | <percentage> | auto | inherit
2076 case CSSPropertyRight: // <length> | <percentage> | auto | inherit
2077 case CSSPropertyTop: // <length> | <percentage> | auto | inherit
2078 case CSSPropertyMarginTop: //// <margin-width> | inherit
2079 case CSSPropertyMarginRight: // Which is defined as
2080 case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit
2081 case CSSPropertyMarginLeft: ////
2082 case CSSPropertyWebkitMarginStart:
2083 case CSSPropertyWebkitMarginEnd:
2084 case CSSPropertyWebkitMarginBefore:
2085 case CSSPropertyWebkitMarginAfter:
2086 if (id == CSSValueAuto)
2087 validPrimitive = true;
2089 validPrimitive = (!id && validUnit(value, FLength | FPercent));
2092 case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
2093 case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
2094 if (id == CSSValueAuto)
2095 validPrimitive = true;
2097 validPrimitive = (!id && validUnit(value, FPositiveInteger, HTMLQuirksMode));
2100 case CSSPropertyZIndex: // auto | <integer> | inherit
2101 if (id == CSSValueAuto)
2102 validPrimitive = true;
2104 validPrimitive = (!id && validUnit(value, FInteger, HTMLQuirksMode));
2107 case CSSPropertyLineHeight:
2108 return parseLineHeight(important);
2109 case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
2110 if (id != CSSValueNone)
2111 return parseCounter(propId, 1, important);
2112 validPrimitive = true;
2114 case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit
2115 if (id != CSSValueNone)
2116 return parseCounter(propId, 0, important);
2117 validPrimitive = true;
2119 case CSSPropertyFontFamily:
2120 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
2122 parsedValue = parseFontFamily();
2126 case CSSPropertyTextDecoration:
2127 // Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration
2128 // is disabled to match CSS 2.1 rules for parsing 'text-decoration'.
2129 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) {
2130 // [ <text-decoration-line> || <text-decoration-style> || <text-decoration-color> ] | inherit
2131 return parseShorthand(CSSPropertyTextDecoration, textDecorationShorthand(), important);
2133 case CSSPropertyWebkitTextDecorationsInEffect:
2134 case CSSPropertyTextDecorationLine:
2135 // none | [ underline || overline || line-through || blink ] | inherit
2136 return parseTextDecoration(propId, important);
2138 case CSSPropertyTextDecorationStyle:
2139 // solid | double | dotted | dashed | wavy
2140 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()
2141 && (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDotted || id == CSSValueDashed || id == CSSValueWavy))
2142 validPrimitive = true;
2145 case CSSPropertyTextUnderlinePosition:
2146 // auto | under | inherit
2147 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled())
2148 return parseTextUnderlinePosition(important);
2151 case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit
2152 if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
2153 validPrimitive = true;
2155 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode));
2158 case CSSPropertySrc: // Only used within @font-face and @-webkit-filter, so cannot use inherit | initial or be !important. This is a list of urls or local references.
2159 return parseFontFaceSrc();
2161 case CSSPropertyUnicodeRange:
2162 return parseFontFaceUnicodeRange();
2164 /* CSS3 properties */
2166 case CSSPropertyBorderImage:
2167 case CSSPropertyWebkitMaskBoxImage:
2168 return parseBorderImageShorthand(propId, important);
2169 case CSSPropertyWebkitBorderImage: {
2170 if (RefPtr<CSSValue> result = parseBorderImage(propId)) {
2171 addProperty(propId, result, important);
2177 case CSSPropertyBorderImageOutset:
2178 case CSSPropertyWebkitMaskBoxImageOutset: {
2179 RefPtr<CSSPrimitiveValue> result;
2180 if (parseBorderImageOutset(result)) {
2181 addProperty(propId, result, important);
2186 case CSSPropertyBorderImageRepeat:
2187 case CSSPropertyWebkitMaskBoxImageRepeat: {
2188 RefPtr<CSSValue> result;
2189 if (parseBorderImageRepeat(result)) {
2190 addProperty(propId, result, important);
2195 case CSSPropertyBorderImageSlice:
2196 case CSSPropertyWebkitMaskBoxImageSlice: {
2197 RefPtr<CSSBorderImageSliceValue> result;
2198 if (parseBorderImageSlice(propId, result)) {
2199 addProperty(propId, result, important);
2204 case CSSPropertyBorderImageWidth:
2205 case CSSPropertyWebkitMaskBoxImageWidth: {
2206 RefPtr<CSSPrimitiveValue> result;
2207 if (parseBorderImageWidth(result)) {
2208 addProperty(propId, result, important);
2213 case CSSPropertyBorderTopRightRadius:
2214 case CSSPropertyBorderTopLeftRadius:
2215 case CSSPropertyBorderBottomLeftRadius:
2216 case CSSPropertyBorderBottomRightRadius: {
2217 if (num != 1 && num != 2)
2219 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2220 if (!validPrimitive)
2222 RefPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
2223 RefPtr<CSSPrimitiveValue> parsedValue2;
2225 value = m_valueList->next();
2226 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2227 if (!validPrimitive)
2229 parsedValue2 = createPrimitiveNumericValue(value);
2231 parsedValue2 = parsedValue1;
2233 addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important);
2236 case CSSPropertyTabSize:
2237 validPrimitive = validUnit(value, FInteger | FNonNeg);
2239 case CSSPropertyWebkitAspectRatio:
2240 return parseAspectRatio(important);
2241 case CSSPropertyBorderRadius:
2242 case CSSPropertyWebkitBorderRadius:
2243 return parseBorderRadius(propId, important);
2244 case CSSPropertyOutlineOffset:
2245 validPrimitive = validUnit(value, FLength);
2247 case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
2248 case CSSPropertyBoxShadow:
2249 case CSSPropertyWebkitBoxShadow:
2250 if (id == CSSValueNone)
2251 validPrimitive = true;
2253 RefPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
2254 if (shadowValueList) {
2255 addProperty(propId, shadowValueList.release(), important);
2256 m_valueList->next();
2262 case CSSPropertyWebkitBoxReflect:
2263 if (id == CSSValueNone)
2264 validPrimitive = true;
2266 return parseReflect(propId, important);
2268 case CSSPropertyOpacity:
2269 validPrimitive = validUnit(value, FNumber);
2271 case CSSPropertyWebkitBoxFlex:
2272 validPrimitive = validUnit(value, FNumber);
2274 case CSSPropertyWebkitBoxFlexGroup:
2275 validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode);
2277 case CSSPropertyWebkitBoxOrdinalGroup:
2278 validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode) && value->fValue;
2280 case CSSPropertyWebkitFilter:
2281 if (id == CSSValueNone)
2282 validPrimitive = true;
2284 RefPtr<CSSValue> val = parseFilter();
2286 addProperty(propId, val, important);
2292 case CSSPropertyFlex: {
2293 ShorthandScope scope(this, propId);
2294 if (id == CSSValueNone) {
2295 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
2296 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
2297 addProperty(CSSPropertyFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
2300 return parseFlex(m_valueList.get(), important);
2302 case CSSPropertyFlexBasis:
2303 // FIXME: Support intrinsic dimensions too.
2304 if (id == CSSValueAuto)
2305 validPrimitive = true;
2307 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
2309 case CSSPropertyFlexGrow:
2310 case CSSPropertyFlexShrink:
2311 validPrimitive = validUnit(value, FNumber | FNonNeg);
2313 case CSSPropertyOrder:
2314 if (validUnit(value, FInteger, HTMLStandardMode)) {
2315 if (!isVariableReference(value)) {
2316 // We restrict the smallest value to int min + 2 because we use int min and int min + 1 as special values in a hash set.
2317 parsedValue = cssValuePool().createValue(max(static_cast<double>(std::numeric_limits<int>::min() + 2), value->fValue),
2318 static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
2319 m_valueList->next();
2321 validPrimitive = true;
2325 case CSSPropertyInternalMarqueeIncrement:
2326 if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
2327 validPrimitive = true;
2329 validPrimitive = validUnit(value, FLength | FPercent);
2331 case CSSPropertyInternalMarqueeRepetition:
2332 if (id == CSSValueInfinite)
2333 validPrimitive = true;
2335 validPrimitive = validUnit(value, FInteger | FNonNeg);
2337 case CSSPropertyInternalMarqueeSpeed:
2338 if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
2339 validPrimitive = true;
2341 validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
2343 case CSSPropertyWebkitFlowInto:
2344 if (!RuntimeEnabledFeatures::cssRegionsEnabled())
2346 return parseFlowThread(propId, important);
2347 case CSSPropertyWebkitFlowFrom:
2348 if (!RuntimeEnabledFeatures::cssRegionsEnabled())
2350 return parseRegionThread(propId, important);
2351 case CSSPropertyWebkitTransform:
2352 if (id == CSSValueNone)
2353 validPrimitive = true;
2355 RefPtr<CSSValue> transformValue = parseTransform();
2356 if (transformValue) {
2357 addProperty(propId, transformValue.release(), important);
2363 case CSSPropertyWebkitTransformOrigin:
2364 case CSSPropertyWebkitTransformOriginX:
2365 case CSSPropertyWebkitTransformOriginY:
2366 case CSSPropertyWebkitTransformOriginZ: {
2367 RefPtr<CSSValue> val1;
2368 RefPtr<CSSValue> val2;
2369 RefPtr<CSSValue> val3;
2370 CSSPropertyID propId1, propId2, propId3;
2371 if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
2372 addProperty(propId1, val1.release(), important);
2374 addProperty(propId2, val2.release(), important);
2376 addProperty(propId3, val3.release(), important);
2381 case CSSPropertyWebkitPerspective:
2382 if (id == CSSValueNone)
2383 validPrimitive = true;
2385 // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
2386 if (validUnit(value, FNumber | FLength | FNonNeg)) {
2387 RefPtr<CSSValue> val = createPrimitiveNumericValue(value);
2389 addProperty(propId, val.release(), important);
2396 case CSSPropertyWebkitPerspectiveOrigin:
2397 case CSSPropertyWebkitPerspectiveOriginX:
2398 case CSSPropertyWebkitPerspectiveOriginY: {
2399 RefPtr<CSSValue> val1;
2400 RefPtr<CSSValue> val2;
2401 CSSPropertyID propId1, propId2;
2402 if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
2403 addProperty(propId1, val1.release(), important);
2405 addProperty(propId2, val2.release(), important);
2410 case CSSPropertyAnimationDelay:
2411 case CSSPropertyAnimationDirection:
2412 case CSSPropertyAnimationDuration:
2413 case CSSPropertyAnimationFillMode:
2414 case CSSPropertyAnimationName:
2415 case CSSPropertyAnimationPlayState:
2416 case CSSPropertyAnimationIterationCount:
2417 case CSSPropertyAnimationTimingFunction:
2418 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
2420 case CSSPropertyWebkitAnimationDelay:
2421 case CSSPropertyWebkitAnimationDirection:
2422 case CSSPropertyWebkitAnimationDuration:
2423 case CSSPropertyWebkitAnimationFillMode:
2424 case CSSPropertyWebkitAnimationName:
2425 case CSSPropertyWebkitAnimationPlayState:
2426 case CSSPropertyWebkitAnimationIterationCount:
2427 case CSSPropertyWebkitAnimationTimingFunction:
2428 case CSSPropertyTransitionDelay:
2429 case CSSPropertyTransitionDuration:
2430 case CSSPropertyTransitionTimingFunction:
2431 case CSSPropertyTransitionProperty:
2432 case CSSPropertyWebkitTransitionDelay:
2433 case CSSPropertyWebkitTransitionDuration:
2434 case CSSPropertyWebkitTransitionTimingFunction:
2435 case CSSPropertyWebkitTransitionProperty: {
2436 RefPtr<CSSValue> val;
2437 AnimationParseContext context;
2438 if (parseAnimationProperty(propId, val, context)) {
2439 addPropertyWithPrefixingVariant(propId, val.release(), important);
2445 case CSSPropertyJustifySelf:
2446 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2449 return parseItemPositionOverflowPosition(propId, important);
2450 case CSSPropertyGridAutoColumns:
2451 case CSSPropertyGridAutoRows:
2452 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2454 parsedValue = parseGridTrackSize(*m_valueList);
2457 case CSSPropertyGridDefinitionColumns:
2458 case CSSPropertyGridDefinitionRows:
2459 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2461 return parseGridTrackList(propId, important);
2463 case CSSPropertyGridColumnEnd:
2464 case CSSPropertyGridColumnStart:
2465 case CSSPropertyGridRowEnd:
2466 case CSSPropertyGridRowStart:
2467 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2469 parsedValue = parseGridPosition();
2472 case CSSPropertyGridColumn:
2473 case CSSPropertyGridRow:
2474 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2476 return parseGridItemPositionShorthand(propId, important);
2478 case CSSPropertyGridArea:
2479 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2481 return parseGridAreaShorthand(important);
2483 case CSSPropertyGridTemplate:
2484 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2486 parsedValue = parseGridTemplate();
2489 case CSSPropertyWebkitMarginCollapse: {
2491 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2492 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important))
2494 CSSValue* value = m_parsedProperties.last().value();
2495 addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
2498 else if (num == 2) {
2499 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2500 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important) || !parseValue(webkitMarginCollapseShorthand().properties()[1], important))
2506 case CSSPropertyTextLineThroughWidth:
2507 case CSSPropertyTextOverlineWidth:
2508 case CSSPropertyTextUnderlineWidth:
2509 if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
2510 id == CSSValueMedium || id == CSSValueThick)
2511 validPrimitive = true;
2513 validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent);
2515 case CSSPropertyWebkitColumnCount:
2516 parsedValue = parseColumnCount();
2518 case CSSPropertyWebkitColumnGap: // normal | <length>
2519 if (id == CSSValueNormal)
2520 validPrimitive = true;
2522 validPrimitive = validUnit(value, FLength | FNonNeg);
2524 case CSSPropertyWebkitColumnAxis:
2525 if (id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
2526 validPrimitive = true;
2528 case CSSPropertyWebkitColumnProgression:
2529 if (id == CSSValueNormal || id == CSSValueReverse)
2530 validPrimitive = true;
2532 case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property)
2533 if (id == CSSValueAll || id == CSSValueNone)
2534 validPrimitive = true;
2536 validPrimitive = validUnit(value, FNumber | FNonNeg) && value->fValue == 1;
2538 case CSSPropertyWebkitColumnWidth: // auto | <length>
2539 parsedValue = parseColumnWidth();
2541 // End of CSS3 properties
2543 // Apple specific properties. These will never be standardized and are purely to
2544 // support custom WebKit-based Apple applications.
2545 case CSSPropertyWebkitLineClamp:
2546 // When specifying number of lines, don't allow 0 as a valid value
2547 // When specifying either type of unit, require non-negative integers
2548 validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, HTMLQuirksMode));
2551 case CSSPropertyWebkitFontSizeDelta: // <length>
2552 validPrimitive = validUnit(value, FLength);
2555 case CSSPropertyWebkitHighlight:
2556 if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
2557 validPrimitive = true;
2560 case CSSPropertyWebkitHyphenateCharacter:
2561 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2562 validPrimitive = true;
2565 case CSSPropertyWebkitLineGrid:
2566 if (id == CSSValueNone)
2567 validPrimitive = true;
2568 else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
2569 String lineGridValue = String(value->string);
2570 if (!lineGridValue.isEmpty()) {
2571 addProperty(propId, cssValuePool().createValue(lineGridValue, CSSPrimitiveValue::CSS_STRING), important);
2576 case CSSPropertyWebkitLocale:
2577 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2578 validPrimitive = true;
2581 // End Apple-specific properties
2583 case CSSPropertyWebkitAppRegion:
2584 if (id >= CSSValueDrag && id <= CSSValueNoDrag)
2585 validPrimitive = true;
2588 case CSSPropertyWebkitTapHighlightColor:
2589 if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu
2590 || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
2591 validPrimitive = true;
2593 parsedValue = parseColor();
2595 m_valueList->next();
2599 /* shorthand properties */
2600 case CSSPropertyBackground: {
2601 // Position must come before color in this array because a plain old "0" is a legal color
2602 // in quirks mode but it's usually the X coordinate of a position.
2603 const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
2604 CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
2605 CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
2606 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
2608 case CSSPropertyWebkitMask: {
2609 const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
2610 CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize };
2611 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
2613 case CSSPropertyBorder:
2614 // [ 'border-width' || 'border-style' || <color> ] | inherit
2616 if (parseShorthand(propId, parsingShorthandForProperty(CSSPropertyBorder), important)) {
2617 // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as
2618 // though a value of none was specified for the image.
2619 addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
2624 case CSSPropertyBorderTop:
2625 // [ 'border-top-width' || 'border-style' || <color> ] | inherit
2626 return parseShorthand(propId, borderTopShorthand(), important);
2627 case CSSPropertyBorderRight:
2628 // [ 'border-right-width' || 'border-style' || <color> ] | inherit
2629 return parseShorthand(propId, borderRightShorthand(), important);
2630 case CSSPropertyBorderBottom:
2631 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
2632 return parseShorthand(propId, borderBottomShorthand(), important);
2633 case CSSPropertyBorderLeft:
2634 // [ 'border-left-width' || 'border-style' || <color> ] | inherit
2635 return parseShorthand(propId, borderLeftShorthand(), important);
2636 case CSSPropertyWebkitBorderStart:
2637 return parseShorthand(propId, webkitBorderStartShorthand(), important);
2638 case CSSPropertyWebkitBorderEnd:
2639 return parseShorthand(propId, webkitBorderEndShorthand(), important);
2640 case CSSPropertyWebkitBorderBefore:
2641 return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
2642 case CSSPropertyWebkitBorderAfter:
2643 return parseShorthand(propId, webkitBorderAfterShorthand(), important);
2644 case CSSPropertyOutline:
2645 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
2646 return parseShorthand(propId, outlineShorthand(), important);
2647 case CSSPropertyBorderColor:
2648 // <color>{1,4} | inherit
2649 return parse4Values(propId, borderColorShorthand().properties(), important);
2650 case CSSPropertyBorderWidth:
2651 // <border-width>{1,4} | inherit
2652 return parse4Values(propId, borderWidthShorthand().properties(), important);
2653 case CSSPropertyBorderStyle:
2654 // <border-style>{1,4} | inherit
2655 return parse4Values(propId, borderStyleShorthand().properties(), important);
2656 case CSSPropertyMargin:
2657 // <margin-width>{1,4} | inherit
2658 return parse4Values(propId, marginShorthand().properties(), important);
2659 case CSSPropertyPadding:
2660 // <padding-width>{1,4} | inherit
2661 return parse4Values(propId, paddingShorthand().properties(), important);
2662 case CSSPropertyFlexFlow:
2663 return parseShorthand(propId, flexFlowShorthand(), important);
2664 case CSSPropertyFont:
2665 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
2666 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
2667 if (id >= CSSValueCaption && id <= CSSValueStatusBar)
2668 validPrimitive = true;
2670 return parseFont(important);
2672 case CSSPropertyListStyle:
2673 return parseShorthand(propId, listStyleShorthand(), important);
2674 case CSSPropertyWebkitColumns:
2675 return parseColumnsShorthand(important);
2676 case CSSPropertyWebkitColumnRule:
2677 return parseShorthand(propId, webkitColumnRuleShorthand(), important);
2678 case CSSPropertyWebkitTextStroke:
2679 return parseShorthand(propId, webkitTextStrokeShorthand(), important);
2680 case CSSPropertyAnimation:
2681 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
2683 case CSSPropertyWebkitAnimation:
2684 return parseAnimationShorthand(propId, important);
2685 case CSSPropertyTransition:
2686 case CSSPropertyWebkitTransition:
2687 return parseTransitionShorthand(propId, important);
2688 case CSSPropertyInvalid:
2690 case CSSPropertyPage:
2691 return parsePage(propId, important);
2692 case CSSPropertyFontStretch:
2694 // CSS Text Layout Module Level 3: Vertical writing support
2695 case CSSPropertyWebkitTextEmphasis:
2696 return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
2698 case CSSPropertyWebkitTextEmphasisStyle:
2699 return parseTextEmphasisStyle(important);
2701 case CSSPropertyWebkitTextOrientation:
2702 // FIXME: For now just support sideways, sideways-right, upright and vertical-right.
2703 if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSValueVerticalRight || id == CSSValueUpright)
2704 validPrimitive = true;
2707 case CSSPropertyWebkitLineBoxContain:
2708 if (id == CSSValueNone)
2709 validPrimitive = true;
2711 return parseLineBoxContain(important);
2713 case CSSPropertyWebkitFontFeatureSettings:
2714 if (id == CSSValueNormal)
2715 validPrimitive = true;
2717 return parseFontFeatureSettings(important);
2720 case CSSPropertyWebkitFontVariantLigatures:
2721 if (id == CSSValueNormal)
2722 validPrimitive = true;
2724 return parseFontVariantLigatures(important);
2726 case CSSPropertyWebkitClipPath:
2727 if (id == CSSValueNone) {
2728 validPrimitive = true;
2729 } else if (value->unit == CSSParserValue::Function) {
2730 parsedValue = parseBasicShape();
2731 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
2732 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
2733 addProperty(propId, parsedValue.release(), important);
2737 case CSSPropertyShapeInside:
2738 case CSSPropertyShapeOutside:
2739 parsedValue = parseShapeProperty(propId);
2741 case CSSPropertyShapeMargin:
2742 case CSSPropertyShapePadding:
2743 validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FLength | FNonNeg));
2745 case CSSPropertyShapeImageThreshold:
2746 validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FNumber));
2749 case CSSPropertyTouchAction:
2750 // auto | none | [pan-x || pan-y]
2751 return parseTouchAction(important);
2753 case CSSPropertyAlignSelf:
2754 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
2755 return parseItemPositionOverflowPosition(propId, important);
2757 case CSSPropertyAlignItems:
2758 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
2759 return parseItemPositionOverflowPosition(propId, important);
2761 case CSSPropertyBorderBottomStyle:
2762 case CSSPropertyBorderCollapse:
2763 case CSSPropertyBorderLeftStyle:
2764 case CSSPropertyBorderRightStyle:
2765 case CSSPropertyBorderTopStyle:
2766 case CSSPropertyBoxSizing:
2767 case CSSPropertyCaptionSide:
2768 case CSSPropertyClear:
2769 case CSSPropertyDirection:
2770 case CSSPropertyDisplay:
2771 case CSSPropertyEmptyCells:
2772 case CSSPropertyFloat:
2773 case CSSPropertyFontStyle:
2774 case CSSPropertyImageRendering:
2775 case CSSPropertyListStylePosition:
2776 case CSSPropertyListStyleType:
2777 case CSSPropertyObjectFit:
2778 case CSSPropertyOutlineStyle:
2779 case CSSPropertyOverflowWrap:
2780 case CSSPropertyOverflowX:
2781 case CSSPropertyOverflowY:
2782 case CSSPropertyPageBreakAfter:
2783 case CSSPropertyPageBreakBefore:
2784 case CSSPropertyPageBreakInside:
2785 case CSSPropertyPointerEvents:
2786 case CSSPropertyPosition:
2787 case CSSPropertyResize:
2788 case CSSPropertySpeak:
2789 case CSSPropertyTableLayout:
2790 case CSSPropertyTextAlignLast:
2791 case CSSPropertyTextJustify:
2792 case CSSPropertyTextLineThroughMode:
2793 case CSSPropertyTextLineThroughStyle:
2794 case CSSPropertyTextOverflow:
2795 case CSSPropertyTextOverlineMode:
2796 case CSSPropertyTextOverlineStyle:
2797 case CSSPropertyTextRendering:
2798 case CSSPropertyTextTransform:
2799 case CSSPropertyTextUnderlineMode:
2800 case CSSPropertyTextUnderlineStyle:
2801 case CSSPropertyTouchActionDelay:
2802 case CSSPropertyVariable:
2803 case CSSPropertyVisibility:
2804 case CSSPropertyWebkitAppearance:
2805 case CSSPropertyWebkitBackfaceVisibility:
2806 case CSSPropertyWebkitBorderAfterStyle:
2807 case CSSPropertyWebkitBorderBeforeStyle:
2808 case CSSPropertyWebkitBorderEndStyle:
2809 case CSSPropertyWebkitBorderFit:
2810 case CSSPropertyWebkitBorderStartStyle:
2811 case CSSPropertyWebkitBoxAlign:
2812 case CSSPropertyWebkitBoxDecorationBreak:
2813 case CSSPropertyWebkitBoxDirection:
2814 case CSSPropertyWebkitBoxLines:
2815 case CSSPropertyWebkitBoxOrient:
2816 case CSSPropertyWebkitBoxPack:
2817 case CSSPropertyInternalCallback:
2818 case CSSPropertyWebkitColumnBreakAfter:
2819 case CSSPropertyWebkitColumnBreakBefore:
2820 case CSSPropertyWebkitColumnBreakInside:
2821 case CSSPropertyColumnFill:
2822 case CSSPropertyWebkitColumnRuleStyle:
2823 case CSSPropertyAlignContent:
2824 case CSSPropertyFlexDirection:
2825 case CSSPropertyFlexWrap:
2826 case CSSPropertyJustifyContent:
2827 case CSSPropertyFontKerning:
2828 case CSSPropertyWebkitFontSmoothing:
2829 case CSSPropertyGridAutoFlow:
2830 case CSSPropertyWebkitLineAlign:
2831 case CSSPropertyWebkitLineBreak:
2832 case CSSPropertyWebkitLineSnap:
2833 case CSSPropertyWebkitMarginAfterCollapse:
2834 case CSSPropertyWebkitMarginBeforeCollapse:
2835 case CSSPropertyWebkitMarginBottomCollapse:
2836 case CSSPropertyWebkitMarginTopCollapse:
2837 case CSSPropertyInternalMarqueeDirection:
2838 case CSSPropertyInternalMarqueeStyle:
2839 case CSSPropertyWebkitPrintColorAdjust:
2840 case CSSPropertyWebkitRegionBreakAfter:
2841 case CSSPropertyWebkitRegionBreakBefore:
2842 case CSSPropertyWebkitRegionBreakInside:
2843 case CSSPropertyWebkitRegionFragment:
2844 case CSSPropertyWebkitRtlOrdering:
2845 case CSSPropertyWebkitRubyPosition:
2846 case CSSPropertyWebkitTextCombine:
2847 case CSSPropertyWebkitTextEmphasisPosition:
2848 case CSSPropertyWebkitTextSecurity:
2849 case CSSPropertyWebkitTransformStyle:
2850 case CSSPropertyWebkitUserDrag:
2851 case CSSPropertyWebkitUserModify:
2852 case CSSPropertyWebkitUserSelect:
2853 case CSSPropertyWebkitWrapFlow:
2854 case CSSPropertyWebkitWrapThrough:
2855 case CSSPropertyWebkitWritingMode:
2856 case CSSPropertyWhiteSpace:
2857 case CSSPropertyWordBreak:
2858 case CSSPropertyWordWrap:
2859 case CSSPropertyMixBlendMode:
2860 case CSSPropertyIsolation:
2861 // These properties should be handled before in isValidKeywordPropertyAndValue().
2862 ASSERT_NOT_REACHED();
2864 // Properties below are validated inside parseViewportProperty, because we
2865 // check for parser state. We need to invalidate if someone adds them outside
2866 // a @viewport rule.
2867 case CSSPropertyMaxZoom:
2868 case CSSPropertyMinZoom:
2869 case CSSPropertyOrientation:
2870 case CSSPropertyUserZoom:
2871 validPrimitive = false;
2874 return parseSVGValue(propId, important);
2877 if (validPrimitive) {
2878 parsedValue = parseValidPrimitive(id, value);
2879 m_valueList->next();
2881 ASSERT(!m_parsedCalculation);
2883 if (!m_valueList->current() || inShorthand()) {
2884 addProperty(propId, parsedValue.release(), important);
2891 void BisonCSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
2894 if (lval->isBaseValueList())
2895 toCSSValueList(lval.get())->append(rval);
2897 PassRefPtr<CSSValue> oldlVal(lval.release());
2898 PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
2899 list->append(oldlVal);
2908 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue)
2910 if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
2911 || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
2912 cssValue = cssValuePool().createIdentifierValue(parserValue->id);
2918 bool BisonCSSParser::useLegacyBackgroundSizeShorthandBehavior() const
2920 return m_context.useLegacyBackgroundSizeShorthandBehavior();
2923 const int cMaxFillProperties = 9;
2925 bool BisonCSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
2927 ASSERT(numProperties <= cMaxFillProperties);
2928 if (numProperties > cMaxFillProperties)
2931 ShorthandScope scope(this, propId);
2933 bool parsedProperty[cMaxFillProperties] = { false };
2934 RefPtr<CSSValue> values[cMaxFillProperties];
2935 RefPtr<CSSValue> clipValue;
2936 RefPtr<CSSValue> positionYValue;
2937 RefPtr<CSSValue> repeatYValue;
2938 bool foundClip = false;
2940 bool foundPositionCSSProperty = false;
2942 while (m_valueList->current()) {
2943 CSSParserValue* val = m_valueList->current();
2944 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
2945 // We hit the end. Fill in all remaining values with the initial value.
2946 m_valueList->next();
2947 for (i = 0; i < numProperties; ++i) {
2948 if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
2949 // Color is not allowed except as the last item in a list for backgrounds.
2950 // Reject the entire property.
2953 if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
2954 addFillValue(values[i], cssValuePool().createImplicitInitialValue());
2955 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2956 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
2957 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2958 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
2959 if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
2960 // If background-origin wasn't present, then reset background-clip also.
2961 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
2964 parsedProperty[i] = false;
2966 if (!m_valueList->current())
2970 bool sizeCSSPropertyExpected = false;
2971 if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
2972 sizeCSSPropertyExpected = true;
2973 m_valueList->next();
2976 foundPositionCSSProperty = false;
2978 for (i = 0; !found && i < numProperties; ++i) {
2980 if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgroundSize && properties[i] != CSSPropertyWebkitMaskSize))
2982 if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgroundSize || properties[i] == CSSPropertyWebkitMaskSize))
2985 if (!parsedProperty[i]) {
2986 RefPtr<CSSValue> val1;
2987 RefPtr<CSSValue> val2;
2988 CSSPropertyID propId1, propId2;
2989 CSSParserValue* parserValue = m_valueList->current();
2990 // parseFillProperty() may modify m_implicitShorthand, so we MUST reset it
2991 // before EACH return below.
2992 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
2993 parsedProperty[i] = found = true;
2994 addFillValue(values[i], val1.release());
2995 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2996 addFillValue(positionYValue, val2.release());
2997 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2998 addFillValue(repeatYValue, val2.release());
2999 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
3000 // Reparse the value as a clip, and see if we succeed.
3001 if (parseBackgroundClip(parserValue, val1))
3002 addFillValue(clipValue, val1.release()); // The property parsed successfully.
3004 addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
3006 if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
3008 addFillValue(clipValue, val1.release());
3011 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
3012 foundPositionCSSProperty = true;
3017 // if we didn't find at least one match, this is an
3018 // invalid shorthand and we have to ignore it
3020 m_implicitShorthand = false;
3025 // Now add all of the properties we found.
3026 for (i = 0; i < numProperties; i++) {
3027 // Fill in any remaining properties with the initial value.
3028 if (!parsedProperty[i]) {
3029 addFillValue(values[i], cssValuePool().createImplicitInitialValue());
3030 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
3031 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
3032 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
3033 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
3034 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
3035 // If background-origin wasn't present, then reset background-clip also.
3036 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
3039 if (properties[i] == CSSPropertyBackgroundPosition) {
3040 addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
3041 // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
3042 addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
3043 } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
3044 addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
3045 // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
3046 addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
3047 } else if (properties[i] == CSSPropertyBackgroundRepeat) {
3048 addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
3049 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
3050 addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
3051 } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
3052 addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
3053 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
3054 addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
3055 } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
3056 // Value is already set while updating origin
3058 else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i] && useLegacyBackgroundSizeShorthandBehavior())
3061 addProperty(properties[i], values[i].release(), important);
3063 // Add in clip values when we hit the corresponding origin property.
3064 if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
3065 addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
3066 else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
3067 addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
3070 m_implicitShorthand = false;
3074 void BisonCSSParser::storeVariableDeclaration(const CSSParserString& name, PassOwnPtr<CSSParserValueList> value, bool important)
3076 // When CSSGrammar.y encounters an invalid declaration it passes null for the CSSParserValueList, just bail.
3080 static const unsigned prefixLength = sizeof("var-") - 1;
3082 ASSERT(name.length() > prefixLength);
3083 AtomicString variableReference = name.atomicSubstring(prefixLength, name.length() - prefixLength);
3085 StringBuilder builder;
3086 for (unsigned i = 0, size = value->size(); i < size; i++) {
3088 builder.append(' ');
3089 RefPtr<CSSValue> cssValue = value->valueAt(i)->createCSSValue();
3092 builder.append(cssValue->cssText());
3095 addProperty(CSSPropertyVariable, CSSVariableValue::create(variableReference, builder.toString()), important, false);
3098 void BisonCSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
3101 if (lval->isValueList())
3102 toCSSValueList(lval.get())->append(rval);
3104 PassRefPtr<CSSValue> oldVal(lval.release());
3105 PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
3106 list->append(oldVal);
3115 bool BisonCSSParser::parseAnimationShorthand(CSSPropertyID propId, bool important)
3117 const StylePropertyShorthand& animationProperties = parsingShorthandForProperty(propId);
3118 const unsigned numProperties = 8;
3120 // The list of properties in the shorthand should be the same
3121 // length as the list with animation name in last position, even though they are
3122 // in a different order.
3123 ASSERT(numProperties == animationProperties.length());
3124 ASSERT(numProperties == shorthandForProperty(propId).length());
3126 ShorthandScope scope(this, propId);
3128 bool parsedProperty[numProperties] = { false };
3129 AnimationParseContext context;
3130 RefPtr<CSSValue> values[numProperties];
3133 while (m_valueList->current()) {
3134 CSSParserValue* val = m_valueList->current();
3135 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3136 // We hit the end. Fill in all remaining values with the initial value.
3137 m_valueList->next();
3138 for (i = 0; i < numProperties; ++i) {
3139 if (!parsedProperty[i])
3140 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3141 parsedProperty[i] = false;
3143 if (!m_valueList->current())
3145 context.commitFirstAnimation();
3149 for (i = 0; i < numProperties; ++i) {
3150 if (!parsedProperty[i]) {
3151 RefPtr<CSSValue> val;
3152 if (parseAnimationProperty(animationProperties.properties()[i], val, context)) {
3153 parsedProperty[i] = found = true;
3154 addAnimationValue(values[i], val.release());
3160 // if we didn't find at least one match, this is an
3161 // invalid shorthand and we have to ignore it
3166 for (i = 0; i < numProperties; ++i) {
3167 // If we didn't find the property, set an intial value.
3168 if (!parsedProperty[i])
3169 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3171 addProperty(animationProperties.properties()[i], values[i].release(), important);
3177 bool BisonCSSParser::parseTransitionShorthand(CSSPropertyID propId, bool important)
3179 const unsigned numProperties = 4;
3180 const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
3181 ASSERT(numProperties == shorthand.length());
3183 ShorthandScope scope(this, propId);
3185 bool parsedProperty[numProperties] = { false };
3186 AnimationParseContext context;
3187 RefPtr<CSSValue> values[numProperties];
3190 while (m_valueList->current()) {
3191 CSSParserValue* val = m_valueList->current();
3192 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3193 // We hit the end. Fill in all remaining values with the initial value.
3194 m_valueList->next();
3195 for (i = 0; i < numProperties; ++i) {
3196 if (!parsedProperty[i])
3197 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3198 parsedProperty[i] = false;
3200 if (!m_valueList->current())
3202 context.commitFirstAnimation();
3206 for (i = 0; !found && i < numProperties; ++i) {
3207 if (!parsedProperty[i]) {
3208 RefPtr<CSSValue> val;
3209 if (parseAnimationProperty(shorthand.properties()[i], val, context)) {
3210 parsedProperty[i] = found = true;
3211 addAnimationValue(values[i], val.release());
3214 // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid.
3215 if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation())
3220 // if we didn't find at least one match, this is an
3221 // invalid shorthand and we have to ignore it
3226 // Fill in any remaining properties with the initial value.
3227 for (i = 0; i < numProperties; ++i) {
3228 if (!parsedProperty[i])
3229 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3232 // Now add all of the properties we found.
3233 for (i = 0; i < numProperties; i++)
3234 addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].release(), important);
3239 PassRefPtr<CSSValue> BisonCSSParser::parseColumnWidth()
3241 CSSParserValue* value = m_valueList->current();
3242 // Always parse lengths in strict mode here, since it would be ambiguous otherwise when used in
3243 // the 'columns' shorthand property.
3244 if (value->id == CSSValueAuto
3245 || (validUnit(value, FLength | FNonNeg, HTMLStandardMode) && value->fValue)) {
3246 RefPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
3247 m_valueList->next();
3253 PassRefPtr<CSSValue> BisonCSSParser::parseColumnCount()
3255 CSSParserValue* value = m_valueList->current();
3256 if (value->id == CSSValueAuto
3257 || (!value->id && validUnit(value, FPositiveInteger, HTMLQuirksMode))) {
3258 RefPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
3259 m_valueList->next();
3265 bool BisonCSSParser::parseColumnsShorthand(bool important)
3267 RefPtr <CSSValue> columnWidth;
3268 RefPtr <CSSValue> columnCount;
3269 bool hasPendingExplicitAuto = false;
3271 for (unsigned propertiesParsed = 0; CSSParserValue* value = m_valueList->current(); propertiesParsed++) {
3272 if (propertiesParsed >= 2)
3273 return false; // Too many values for this shorthand. Invalid declaration.
3274 if (!propertiesParsed && value->id == CSSValueAuto) {
3275 // 'auto' is a valid value for any of the two longhands, and at this point we
3276 // don't know which one(s) it is meant for. We need to see if there are other
3278 m_valueList->next();
3279 hasPendingExplicitAuto = true;
3282 if ((columnWidth = parseColumnWidth()))
3286 if ((columnCount = parseColumnCount()))
3289 // If we didn't find at least one match, this is an
3290 // invalid shorthand and we have to ignore it.
3294 if (hasPendingExplicitAuto) {
3295 // Time to assign the previously skipped 'auto' value to a property. If both properties are
3296 // unassigned at this point (i.e. 'columns:auto'), it doesn't matter that much which one we
3297 // set (although it does make a slight difference to web-inspector). The one we don't set
3298 // here will get an implicit 'auto' value further down.
3300 columnWidth = cssValuePool().createIdentifierValue(CSSValueAuto);
3302 ASSERT(!columnCount);
3303 columnCount = cssValuePool().createIdentifierValue(CSSValueAuto);
3306 ASSERT(columnCount || columnWidth);
3308 // Any unassigned property at this point will become implicit 'auto'.
3310 addProperty(CSSPropertyWebkitColumnWidth, columnWidth, important);
3312 addProperty(CSSPropertyWebkitColumnWidth, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
3314 addProperty(CSSPropertyWebkitColumnCount, columnCount, important);
3316 addProperty(CSSPropertyWebkitColumnCount, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
3320 bool BisonCSSParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
3322 // We try to match as many properties as possible
3323 // We set up an array of booleans to mark which property has been found,
3324 // and we try to search for properties until it makes no longer any sense.
3325 ShorthandScope scope(this, propId);
3328 unsigned propertiesParsed = 0;
3329 bool propertyFound[6] = { false, false, false, false, false, false }; // 6 is enough size.
3331 while (m_valueList->current()) {
3333 for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
3334 if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
3335 propertyFound[propIndex] = found = true;
3340 // if we didn't find at least one match, this is an
3341 // invalid shorthand and we have to ignore it
3346 if (propertiesParsed == shorthand.length())
3349 // Fill in any remaining properties with the initial value.
3350 ImplicitScope implicitScope(this, PropertyImplicit);
3351 const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization();
3352 for (unsigned i = 0; i < shorthand.length(); ++i) {
3353 if (propertyFound[i])
3356 if (propertiesForInitialization) {
3357 const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]);
3358 for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
3359 addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
3361 addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
3367 bool BisonCSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties, bool important)
3369 /* From the CSS 2 specs, 8.3
3370 * If there is only one value, it applies to all sides. If there are two values, the top and
3371 * bottom margins are set to the first value and the right and left margins are set to the second.
3372 * If there are three values, the top is set to the first value, the left and right are set to the
3373 * second, and the bottom is set to the third. If there are four values, they apply to the top,
3374 * right, bottom, and left, respectively.
3377 int num = inShorthand() ? 1 : m_valueList->size();
3379 ShorthandScope scope(this, propId);
3381 // the order is top, right, bottom, left
3384 if (!parseValue(properties[0], important))
3386 CSSValue* value = m_parsedProperties.last().value();
3387 ImplicitScope implicitScope(this, PropertyImplicit);
3388 addProperty(properties[1], value, important);
3389 addProperty(properties[2], value, important);
3390 addProperty(properties[3], value, important);
3394 if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
3396 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3397 ImplicitScope implicitScope(this, PropertyImplicit);
3398 addProperty(properties[2], value, important);
3399 value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3400 addProperty(properties[3], value, important);
3404 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
3406 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3407 ImplicitScope implicitScope(this, PropertyImplicit);
3408 addProperty(properties[3], value, important);
3412 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
3413 !parseValue(properties[2], important) || !parseValue(properties[3], important))
3425 // auto | <identifier>
3426 bool BisonCSSParser::parsePage(CSSPropertyID propId, bool important)
3428 ASSERT(propId == CSSPropertyPage);
3430 if (m_valueList->size() != 1)
3433 CSSParserValue* value = m_valueList->current();
3437 if (value->id == CSSValueAuto) {
3438 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
3440 } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
3441 addProperty(propId, createPrimitiveStringValue(value), important);
3447 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
3448 bool BisonCSSParser::parseSize(CSSPropertyID propId, bool important)
3450 ASSERT(propId == CSSPropertySize);
3452 if (m_valueList->size() > 2)
3455 CSSParserValue* value = m_valueList->current();
3459 RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
3462 SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
3463 if (paramType == None)
3466 // Second parameter, if any.
3467 value = m_valueList->next();
3469 paramType = parseSizeParameter(parsedValues.get(), value, paramType);
3470 if (paramType == None)
3474 addProperty(propId, parsedValues.release(), important);
3478 BisonCSSParser::SizeParameterType BisonCSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
3480 switch (value->id) {
3482 if (prevParamType == None) {
3483 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3487 case CSSValueLandscape:
3488 case CSSValuePortrait:
3489 if (prevParamType == None || prevParamType == PageSize) {
3490 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3499 case CSSValueLedger:
3501 case CSSValueLetter:
3502 if (prevParamType == None || prevParamType == Orientation) {
3503 // Normalize to Page Size then Orientation order by prepending.
3504 // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
3505 parsedValues->prepend(cssValuePool().createIdentifierValue(value->id));
3510 if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) {
3511 parsedValues->append(createPrimitiveNumericValue(value));
3520 // [ <string> <string> ]+ | inherit | none
3521 // inherit and none are handled in parseValue.
3522 bool BisonCSSParser::parseQuotes(CSSPropertyID propId, bool important)
3524 RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3525 while (CSSParserValue* val = m_valueList->current()) {
3526 RefPtr<CSSValue> parsedValue;
3527 if (val->unit == CSSPrimitiveValue::CSS_STRING)
3528 parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
3531 values->append(parsedValue.release());
3532 m_valueList->next();
3534 if (values->length()) {
3535 addProperty(propId, values.release(), important);
3536 m_valueList->next();
3542 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
3543 // in CSS 2.1 this got somewhat reduced:
3544 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
3545 bool BisonCSSParser::parseContent(CSSPropertyID propId, bool important)
3547 RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3549 while (CSSParserValue* val = m_valueList->current()) {
3550 RefPtr<CSSValue> parsedValue;
3551 if (val->unit == CSSPrimitiveValue::CSS_URI) {
3553 parsedValue = CSSImageValue::create(completeURL(val->string));
3554 } else if (val->unit == CSSParserValue::Function) {
3555 // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
3556 CSSParserValueList* args = val->function->args.get();
3559 if (equalIgnoringCase(val->function->name, "attr(")) {
3560 parsedValue = parseAttr(args);
3563 } else if (equalIgnoringCase(val->function->name, "counter(")) {
3564 parsedValue = parseCounterContent(args, false);
3567 } else if (equalIgnoringCase(val->function->name, "counters(")) {
3568 parsedValue = parseCounterContent(args, true);
3571 } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
3572 parsedValue = parseImageSet(m_valueList.get());
3575 } else if (isGeneratedImageValue(val)) {
3576 if (!parseGeneratedImage(m_valueList.get(), parsedValue))
3580 } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
3586 // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
3590 case CSSValueOpenQuote:
3591 case CSSValueCloseQuote:
3592 case CSSValueNoOpenQuote:
3593 case CSSValueNoCloseQuote:
3595 case CSSValueNormal:
3596 parsedValue = cssValuePool().createIdentifierValue(val->id);
3600 } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
3601 parsedValue = createPrimitiveStringValue(val);
3605 values->append(parsedValue.release());
3606 m_valueList->next();
3609 if (values->length()) {
3610 addProperty(propId, values.release(), important);
3611 m_valueList->next();
3618 PassRefPtr<CSSValue> BisonCSSParser::parseAttr(CSSParserValueList* args)
3620 if (args->size() != 1)
3623 CSSParserValue* a = args->current();
3625 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
3628 String attrName = a->string;
3629 // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
3630 // But HTML attribute names can't have those characters, and we should not
3631 // even parse them inside attr().
3632 if (attrName[0] == '-')
3635 if (m_context.isHTMLDocument())
3636 attrName = attrName.lower();
3638 return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
3641 PassRefPtr<CSSValue> BisonCSSParser::parseBackgroundColor()
3643 CSSValueID id = m_valueList->current()->id;
3644 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
3645 (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
3646 return cssValuePool().createIdentifierValue(id);
3647 return parseColor();
3650 bool BisonCSSParser::parseFillImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
3652 if (valueList->current()->id == CSSValueNone) {
3653 value = cssValuePool().createIdentifierValue(CSSValueNone);
3656 if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
3657 value = CSSImageValue::create(completeURL(valueList->current()->string));
3661 if (isGeneratedImageValue(valueList->current()))
3662 return parseGeneratedImage(valueList, value);
3664 if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) {
3665 value = parseImageSet(m_valueList.get());
3673 PassRefPtr<CSSValue> BisonCSSParser::parseFillPositionX(CSSParserValueList* valueList)
3675 int id = valueList->current()->id;
3676 if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
3678 if (id == CSSValueRight)
3680 else if (id == CSSValueCenter)
3682 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3684 if (validUnit(valueList->current(), FPercent | FLength))
3685 return createPrimitiveNumericValue(valueList->current());
3689 PassRefPtr<CSSValue> BisonCSSParser::parseFillPositionY(CSSParserValueList* valueList)
3691 int id = valueList->current()->id;
3692 if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
3694 if (id == CSSValueBottom)
3696 else if (id == CSSValueCenter)
3698 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3700 if (validUnit(valueList->current(), FPercent | FLength))
3701 return createPrimitiveNumericValue(valueList->current());
3705 PassRefPtr<CSSPrimitiveValue> BisonCSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode)
3707 CSSValueID id = valueList->current()->id;
3708 if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
3710 if (id == CSSValueLeft || id == CSSValueRight) {
3711 if (cumulativeFlags & XFillPosition)
3713 cumulativeFlags |= XFillPosition;
3714 individualFlag = XFillPosition;
3715 if (id == CSSValueRight)
3718 else if (id == CSSValueTop || id == CSSValueBottom) {
3719 if (cumulativeFlags & YFillPosition)
3721 cumulativeFlags |= YFillPosition;
3722 individualFlag = YFillPosition;
3723 if (id == CSSValueBottom)
3725 } else if (id == CSSValueCenter) {
3726 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
3728 cumulativeFlags |= AmbiguousFillPosition;
3729 individualFlag = AmbiguousFillPosition;
3732 if (parsingMode == ResolveValuesAsKeyword)
3733 return cssValuePool().createIdentifierValue(id);
3735 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3737 if (validUnit(valueList->current(), FPercent | FLength)) {
3738 if (!cumulativeFlags) {
3739 cumulativeFlags |= XFillPosition;
3740 individualFlag = XFillPosition;
3741 } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
3742 cumulativeFlags |= YFillPosition;
3743 individualFlag = YFillPosition;
3745 if (m_parsedCalculation)
3746 m_parsedCalculation.release();
3749 return createPrimitiveNumericValue(valueList->current());
3754 static bool isValueConflictingWithCurrentEdge(int value1, int value2)
3756 if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSValueLeft || value2 == CSSValueRight))
3759 if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSValueTop || value2 == CSSValueBottom))
3765 static bool isFillPositionKeyword(CSSValueID value)
3767 return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter;
3770 void BisonCSSParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtr<CSSPrimitiveValue> parsedValue1, PassRefPtr<CSSPrimitiveValue> parsedValue2)
3772 // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <percentage> | <length> ]
3773 // In the case of 4 values <position> requires the second value to be a length or a percentage.
3774 if (isFillPositionKeyword(parsedValue2->getValueID()))
3777 unsigned cumulativeFlags = 0;
3778 FillPositionFlag value3Flag = InvalidFillPosition;
3779 RefPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
3783 CSSValueID ident1 = parsedValue1->getValueID();
3784 CSSValueID ident3 = value3->getValueID();
3786 if (ident1 == CSSValueCenter)
3789 if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
3792 // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
3793 // needed as the second call to parseFillPositionComponent was on purpose not checking it. In the
3794 // case of two values top 20px is invalid but in the case of 4 values it becomes valid.
3795 if (isValueConflictingWithCurrentEdge(ident1, ident3))
3800 cumulativeFlags = 0;
3801 FillPositionFlag value4Flag = InvalidFillPosition;
3802 RefPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(valueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
3806 // 4th value must be a length or a percentage.
3807 if (isFillPositionKeyword(value4->getValueID()))
3810 value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
3811 value2 = createPrimitiveValuePair(value3, value4);
3813 if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
3814 value1.swap(value2);
3818 void BisonCSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtr<CSSPrimitiveValue> parsedValue1, PassRefPtr<CSSPrimitiveValue> parsedValue2)
3820 unsigned cumulativeFlags = 0;
3821 FillPositionFlag value3Flag = InvalidFillPosition;
3822 RefPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
3824 // value3 is not an expected value, we return.
3830 bool swapNeeded = false;
3831 CSSValueID ident1 = parsedValue1->getValueID();
3832 CSSValueID ident2 = parsedValue2->getValueID();
3833 CSSValueID ident3 = value3->getValueID();
3835 CSSValueID firstPositionKeyword;
3836 CSSValueID secondPositionKeyword;
3838 if (ident1 == CSSValueCenter) {
3839 // <position> requires the first 'center' to be followed by a keyword.
3840 if (!isFillPositionKeyword(ident2))
3843 // If 'center' is the first keyword then the last one needs to be a length.
3844 if (isFillPositionKeyword(ident3))
3847 firstPositionKeyword = CSSValueLeft;
3848 if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
3849 firstPositionKeyword = CSSValueTop;
3852 value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
3853 value2 = createPrimitiveValuePair(parsedValue2, value3);
3854 } else if (ident3 == CSSValueCenter) {
3855 if (isFillPositionKeyword(ident2))
3858 secondPositionKeyword = CSSValueTop;
3859 if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
3860 secondPositionKeyword = CSSValueLeft;
3863 value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
3864 value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
3866 RefPtr<CSSPrimitiveValue> firstPositionValue;
3867 RefPtr<CSSPrimitiveValue> secondPositionValue;
3869 if (isFillPositionKeyword(ident2)) {
3870 // To match CSS grammar, we should only accept: [ center | left | right | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ].
3871 ASSERT(ident2 != CSSValueCenter);
3873 if (isFillPositionKeyword(ident3))
3876 secondPositionValue = value3;
3877 secondPositionKeyword = ident2;
3878 firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
3880 // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
3881 if (!isFillPositionKeyword(ident3))
3884 firstPositionValue = parsedValue2;
3885 secondPositionKeyword = ident3;
3886 secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
3889 if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
3892 value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue);
3893 value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue);
3896 if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
3897 value1.swap(value2);
3900 CSSPrimitiveValue* first = toCSSPrimitiveValue(value1.get());
3901 CSSPrimitiveValue* second = toCSSPrimitiveValue(value2.get());
3902 ident1 = first->getPairValue()->first()->getValueID();
3903 ident2 = second->getPairValue()->first()->getValueID();
3904 ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
3905 ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
3909 inline bool BisonCSSParser::isPotentialPositionValue(CSSParserValue* value)
3911 return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue);
3914 void BisonCSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
3916 unsigned numberOfValues = 0;
3917 for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++numberOfValues) {
3918 CSSParserValue* current = valueList->valueAt(i);
3919 if (isComma(current) || !current || isForwardSlashOperator(current) || !isPotentialPositionValue(current))
3923 if (numberOfValues > 4)
3926 // If we are parsing two values, we can safely call the CSS 2.1 parsing function and return.
3927 if (numberOfValues <= 2) {
3928 parse2ValuesFillPosition(valueList, value1, value2);
3932 ASSERT(numberOfValues > 2 && numberOfValues <= 4);
3934 CSSParserValue* value = valueList->current();
3936 // <position> requires the first value to be a background keyword.
3937 if (!isFillPositionKeyword(value->id))
3940 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
3941 unsigned cumulativeFlags = 0;
3942 FillPositionFlag value1Flag = InvalidFillPosition;
3943 FillPositionFlag value2Flag = InvalidFillPosition;
3944 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
3950 // In case we are parsing more than two values, relax the check inside of parseFillPositionComponent. top 20px is
3951 // a valid start for <position>.
3952 cumulativeFlags = AmbiguousFillPosition;
3953 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
3961 RefPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(value1.get());
3962 RefPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(value2.get());
3967 // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
3968 if (parsedValue2->getValueID() == CSSValueCenter)
3971 if (numberOfValues == 3)
3972 parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
3974 parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
3977 void BisonCSSParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
3979 CSSParserValue* value = valueList->current();
3981 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
3982 unsigned cumulativeFlags = 0;
3983 FillPositionFlag value1Flag = InvalidFillPosition;
3984 FillPositionFlag value2Flag = InvalidFillPosition;
3985 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
3989 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
3990 // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the
3991 // value was explicitly specified for our property.
3992 value = valueList->next();
3994 // First check for the comma. If so, we are finished parsing this value or value pair.
3999 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
4003 if (!inShorthand()) {
4011 // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
4012 // is simply 50%. This is our default.
4013 // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
4014 // For left/right/center, the default of 50% in the y is still correct.
4015 value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
4017 if (value1Flag == YFillPosition || value2Flag == XFillPosition)
4018 value1.swap(value2);
4021 void BisonCSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
4023 CSSValueID id = m_valueList->current()->id;
4024 if (id == CSSValueRepeatX) {
4025 m_implicitShorthand = true;
4026 value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
4027 value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
4028 m_valueList->next();
4031 if (id == CSSValueRepeatY) {
4032 m_implicitShorthand = true;
4033 value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
4034 value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
4035 m_valueList->next();
4038 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
4039 value1 = cssValuePool().createIdentifierValue(id);
4045 CSSParserValue* value = m_valueList->next();
4047 // Parse the second value if one is available
4048 if (value && !isComma(value)) {
4050 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
4051 value2 = cssValuePool().createIdentifierValue(id);
4052 m_valueList->next();
4057 // If only one value was specified, value2 is the same as value1.
4058 m_implicitShorthand = true;
4059 value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get())->getValueID());
4062 PassRefPtr<CSSValue> BisonCSSParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
4065 CSSParserValue* value = m_valueList->current();
4067 if (value->id == CSSValueContain || value->id == CSSValueCover)
4068 return cssValuePool().createIdentifierValue(value->id);
4070 RefPtr<CSSPrimitiveValue> parsedValue1;
4072 if (value->id == CSSValueAuto)
4073 parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
4075 if (!validUnit(value, FLength | FPercent))
4077 parsedValue1 = createPrimitiveNumericValue(value);
4080 RefPtr<CSSPrimitiveValue> parsedValue2;
4081 if ((value = m_valueList->next())) {
4082 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
4084 else if (value->id != CSSValueAuto) {
4085 if (!validUnit(value, FLength | FPercent)) {
4088 // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
4089 m_valueList->previous();
4091 parsedValue2 = createPrimitiveNumericValue(value);
4093 } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
4094 // For backwards compatibility we set the second value to the first if it is omitted.
4095 // We only need to do this for -webkit-background-size. It should be safe to let masks match
4096 // the real property.
4097 parsedValue2 = parsedValue1;
4101 return parsedValue1;
4102 return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release());
4105 bool BisonCSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
4106 RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
4108 RefPtr<CSSValueList> values;
4109 RefPtr<CSSValueList> values2;
4110 CSSParserValue* val;
4111 RefPtr<CSSValue> value;
4112 RefPtr<CSSValue> value2;
4114 bool allowComma = false;
4116 retValue1 = retValue2 = 0;
4119 if (propId == CSSPropertyBackgroundPosition) {
4120 propId1 = CSSPropertyBackgroundPositionX;
4121 propId2 = CSSPropertyBackgroundPositionY;
4122 } else if (propId == CSSPropertyWebkitMaskPosition) {
4123 propId1 = CSSPropertyWebkitMaskPositionX;
4124 propId2 = CSSPropertyWebkitMaskPositionY;
4125 } else if (propId == CSSPropertyBackgroundRepeat) {
4126 propId1 = CSSPropertyBackgroundRepeatX;
4127 propId2 = CSSPropertyBackgroundRepeatY;
4128 } else if (propId == CSSPropertyWebkitMaskRepeat) {
4129 propId1 = CSSPropertyWebkitMaskRepeatX;
4130 propId2 = CSSPropertyWebkitMaskRepeatY;
4133 while ((val = m_valueList->current())) {
4134 RefPtr<CSSValue> currValue;
4135 RefPtr<CSSValue> currValue2;
4140 m_valueList->next();
4145 case CSSPropertyBackgroundColor:
4146 currValue = parseBackgroundColor();
4148 m_valueList->next();
4150 case CSSPropertyBackgroundAttachment:
4151 if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
4152 currValue = cssValuePool().createIdentifierValue(val->id);
4153 m_valueList->next();
4156 case CSSPropertyBackgroundImage:
4157 case CSSPropertyWebkitMaskImage:
4158 if (parseFillImage(m_valueList.get(), currValue))
4159 m_valueList->next();
4161 case CSSPropertyWebkitBackgroundClip:
4162 case CSSPropertyWebkitBackgroundOrigin:
4163 case CSSPropertyWebkitMaskClip:
4164 case CSSPropertyWebkitMaskOrigin:
4165 // The first three values here are deprecated and do not apply to the version of the property that has
4166 // the -webkit- prefix removed.
4167 if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
4168 val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
4169 ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
4170 (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
4171 currValue = cssValuePool().createIdentifierValue(val->id);
4172 m_valueList->next();
4175 case CSSPropertyBackgroundClip:
4176 if (parseBackgroundClip(val, currValue))
4177 m_valueList->next();
4179 case CSSPropertyBackgroundOrigin:
4180 if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
4181 currValue = cssValuePool().createIdentifierValue(val->id);
4182 m_valueList->next();
4185 case CSSPropertyBackgroundPosition:
4186 case CSSPropertyWebkitMaskPosition:
4187 parseFillPosition(m_valueList.get(), currValue, currValue2);
4188 // parseFillPosition advances the m_valueList pointer.
4190 case CSSPropertyBackgroundPositionX:
4191 case CSSPropertyWebkitMaskPositionX: {
4192 currValue = parseFillPositionX(m_valueList.get());
4194 m_valueList->next();
4197 case CSSPropertyBackgroundPositionY:
4198 case CSSPropertyWebkitMaskPositionY: {
4199 currValue = parseFillPositionY(m_valueList.get());
4201 m_valueList->next();
4204 case CSSPropertyWebkitBackgroundComposite:
4205 case CSSPropertyWebkitMaskComposite:
4206 if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) {
4207 currValue = cssValuePool().createIdentifierValue(val->id);
4208 m_valueList->next();
4211 case CSSPropertyBackgroundBlendMode:
4212 if (RuntimeEnabledFeatures::cssCompositingEnabled() && (val->id == CSSValueNormal || val->id == CSSValueMultiply
4213 || val->id == CSSValueScreen || val->id == CSSValueOverlay || val->id == CSSValueDarken
4214 || val->id == CSSValueLighten || val->id == CSSValueColorDodge || val->id == CSSValueColorBurn
4215 || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference
4216 || val->id == CSSValueExclusion || val->id == CSSValueHue || val->id == CSSValueSaturation
4217 || val->id == CSSValueColor || val->id == CSSValueLuminosity)) {
4218 currValue = cssValuePool().createIdentifierValue(val->id);
4219 m_valueList->next();
4222 case CSSPropertyBackgroundRepeat:
4223 case CSSPropertyWebkitMaskRepeat:
4224 parseFillRepeat(currValue, currValue2);
4225 // parseFillRepeat advances the m_valueList pointer
4227 case CSSPropertyBackgroundSize:
4228 case CSSPropertyWebkitBackgroundSize:
4229 case CSSPropertyWebkitMaskSize: {
4230 currValue = parseFillSize(propId, allowComma);
4232 m_valueList->next();
4235 case CSSPropertyMaskSourceType: {
4236 if (RuntimeEnabledFeatures::cssMaskSourceTypeEnabled()) {
4237 if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id == CSSValueLuminance) {
4238 currValue = cssValuePool().createIdentifierValue(val->id);
4239 m_valueList->next();
4252 if (value && !values) {
4253 values = CSSValueList::createCommaSeparated();
4254 values->append(value.release());
4257 if (value2 && !values2) {
4258 values2 = CSSValueList::createCommaSeparated();
4259 values2->append(value2.release());
4263 values->append(currValue.release());
4265 value = currValue.release();
4268 values2->append(currValue2.release());
4270 value2 = currValue2.release();
4274 // When parsing any fill shorthand property, we let it handle building up the lists for all
4280 if (values && values->length()) {
4281 retValue1 = values.release();
4282 if (values2 && values2->length())
4283 retValue2 = values2.release();
4287 retValue1 = value.release();
4288 retValue2 = value2.release();
4294 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationDelay()
4296 CSSParserValue* value = m_valueList->current();
4297 if (validUnit(value, FTime))
4298 return createPrimitiveNumericValue(value);
4302 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationDirection()
4304 CSSParserValue* value = m_valueList->current();
4305 if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
4306 return cssValuePool().createIdentifierValue(value->id);
4310 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationDuration()
4312 CSSParserValue* value = m_valueList->current();
4313 if (validUnit(value, FTime | FNonNeg))
4314 return createPrimitiveNumericValue(value);
4318 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationFillMode()
4320 CSSParserValue* value = m_valueList->current();
4321 if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
4322 return cssValuePool().createIdentifierValue(value->id);
4326 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationIterationCount()
4328 CSSParserValue* value = m_valueList->current();
4329 if (value->id == CSSValueInfinite)
4330 return cssValuePool().createIdentifierValue(value->id);
4331 if (validUnit(value, FNumber | FNonNeg))
4332 return createPrimitiveNumericValue(value);
4336 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationName()
4338 CSSParserValue* value = m_valueList->current();
4339 if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
4340 if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value, "none"))) {
4341 return cssValuePool().createIdentifierValue(CSSValueNone);
4343 return createPrimitiveStringValue(value);
4349 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationPlayState()
4351 CSSParserValue* value = m_valueList->current();
4352 if (value->id == CSSValueRunning || value->id == CSSValuePaused)
4353 return cssValuePool().createIdentifierValue(value->id);
4357 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationProperty(AnimationParseContext& context)
4359 CSSParserValue* value = m_valueList->current();
4360 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
4362 CSSPropertyID result = cssPropertyID(value->string);
4364 return cssValuePool().createIdentifierValue(result);
4365 if (equalIgnoringCase(value, "all")) {
4366 context.sawAnimationPropertyKeyword();
4367 return cssValuePool().createIdentifierValue(CSSValueAll);
4369 if (equalIgnoringCase(value, "none")) {
4370 context.commitAnimationPropertyKeyword();
4371 context.sawAnimationPropertyKeyword();
4372 return cssValuePool().createIdentifierValue(CSSValueNone);
4377 bool BisonCSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
4379 parse2ValuesFillPosition(m_valueList.get(), value1, value2);
4382 if (m_valueList->current()) {
4383 if (validUnit(m_valueList->current(), FLength)) {
4384 value3 = createPrimitiveNumericValue(m_valueList->current());
4385 m_valueList->next();
4390 value3 = cssValuePool().createImplicitInitialValue();
4394 bool BisonCSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
4396 CSSParserValue* v = args->current();
4397 if (!validUnit(v, FNumber))
4402 // The last number in the function has no comma after it, so we're done.
4410 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationTimingFunction()
4412 CSSParserValue* value = m_valueList->current();
4413 if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
4414 || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd)
4415 return cssValuePool().createIdentifierValue(value->id);
4417 // We must be a function.
4418 if (value->unit != CSSParserValue::Function)
4421 CSSParserValueList* args = value->function->args.get();
4423 if (equalIgnoringCase(value->function->name, "steps(")) {
4424 // For steps, 1 or 2 params must be specified (comma-separated)
4425 if (!args || (args->size() != 1 && args->size() != 3))
4428 // There are two values.
4430 bool stepAtStart = false;
4432 CSSParserValue* v = args->current();
4433 if (!validUnit(v, FInteger))
4435 numSteps = clampToInteger(v->fValue);
4441 // There is a comma so we need to parse the second value
4445 if (v->id != CSSValueStart && v->id != CSSValueEnd)
4447 stepAtStart = v->id == CSSValueStart;
4450 return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart);
4453 if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
4454 // For cubic bezier, 4 values must be specified.
4455 if (!args || args->size() != 7)
4458 // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range.
4459 double x1, y1, x2, y2;
4461 if (!parseCubicBezierTimingFunctionValue(args, x1))
4463 if (x1 < 0 || x1 > 1)
4465 if (!parseCubicBezierTimingFunctionValue(args, y1))
4467 if (!parseCubicBezierTimingFunctionValue(args, x2))
4469 if (x2 < 0 || x2 > 1)
4471 if (!parseCubicBezierTimingFunctionValue(args, y2))
4474 return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
4480 bool BisonCSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& result, AnimationParseContext& context)
4482 RefPtr<CSSValueList> values;
4483 CSSParserValue* val;
4484 RefPtr<CSSValue> value;
4485 bool allowComma = false;
4489 while ((val = m_valueList->current())) {
4490 RefPtr<CSSValue> currValue;
4494 m_valueList->next();
4499 case CSSPropertyAnimationDelay:
4500 case CSSPropertyWebkitAnimationDelay:
4501 case CSSPropertyTransitionDelay:
4502 case CSSPropertyWebkitTransitionDelay:
4503 currValue = parseAnimationDelay();
4505 m_valueList->next();
4507 case CSSPropertyAnimationDirection:
4508 case CSSPropertyWebkitAnimationDirection:
4509 currValue = parseAnimationDirection();
4511 m_valueList->next();
4513 case CSSPropertyAnimationDuration:
4514 case CSSPropertyWebkitAnimationDuration:
4515 case CSSPropertyTransitionDuration:
4516 case CSSPropertyWebkitTransitionDuration:
4517 currValue = parseAnimationDuration();
4519 m_valueList->next();
4521 case CSSPropertyAnimationFillMode:
4522 case CSSPropertyWebkitAnimationFillMode:
4523 currValue = parseAnimationFillMode();
4525 m_valueList->next();
4527 case CSSPropertyAnimationIterationCount:
4528 case CSSPropertyWebkitAnimationIterationCount:
4529 currValue = parseAnimationIterationCount();
4531 m_valueList->next();
4533 case CSSPropertyAnimationName:
4534 case CSSPropertyWebkitAnimationName:
4535 currValue = parseAnimationName();
4537 m_valueList->next();
4539 case CSSPropertyAnimationPlayState:
4540 case CSSPropertyWebkitAnimationPlayState:
4541 currValue = parseAnimationPlayState();
4543 m_valueList->next();
4545 case CSSPropertyTransitionProperty:
4546 case CSSPropertyWebkitTransitionProperty:
4547 currValue = parseAnimationProperty(context);
4548 if (value && !context.animationPropertyKeywordAllowed())
4551 m_valueList->next();
4553 case CSSPropertyAnimationTimingFunction:
4554 case CSSPropertyWebkitAnimationTimingFunction:
4555 case CSSPropertyTransitionTimingFunction:
4556 case CSSPropertyWebkitTransitionTimingFunction:
4557 currValue = parseAnimationTimingFunction();
4559 m_valueList->next();
4562 ASSERT_NOT_REACHED();
4569 if (value && !values) {
4570 values = CSSValueList::createCommaSeparated();
4571 values->append(value.release());
4575 values->append(currValue.release());
4577 value = currValue.release();
4582 // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
4588 if (values && values->length()) {
4589 result = values.release();
4593 result = value.release();
4599 // The function parses [ <integer> || <string> ] in <grid-line> (which can be stand alone or with 'span').
4600 bool BisonCSSParser::parseIntegerOrStringFromGridPosition(RefPtr<CSSPrimitiveValue>& numericValue, RefPtr<CSSPrimitiveValue>& gridLineName)
4602 CSSParserValue* value = m_valueList->current();
4603 if (validUnit(value, FInteger) && value->fValue) {
4604 numericValue = createPrimitiveNumericValue(value);
4605 value = m_valueList->next();
4606 if (value && value->unit == CSSPrimitiveValue::CSS_STRING) {
4607 gridLineName = createPrimitiveStringValue(m_valueList->current());
4608 m_valueList->next();
4613 if (value->unit == CSSPrimitiveValue::CSS_STRING) {
4614 gridLineName = createPrimitiveStringValue(m_valueList->current());
4615 value = m_valueList->next();
4616 if (value && validUnit(value, FInteger) && value->fValue) {
4617 numericValue = createPrimitiveNumericValue(value);
4618 m_valueList->next();
4626 PassRefPtr<CSSValue> BisonCSSParser::parseGridPosition()
4628 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4630 CSSParserValue* value = m_valueList->current();
4631 if (value->id == CSSValueAuto) {
4632 m_valueList->next();
4633 return cssValuePool().createIdentifierValue(CSSValueAuto);
4636 if (value->id != CSSValueSpan && value->unit == CSSPrimitiveValue::CSS_IDENT) {
4637 m_valueList->next();
4638 return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
4641 RefPtr<CSSPrimitiveValue> numericValue;
4642 RefPtr<CSSPrimitiveValue> gridLineName;
4643 bool hasSeenSpanKeyword = false;
4645 if (parseIntegerOrStringFromGridPosition(numericValue, gridLineName)) {
4646 value = m_valueList->current();
4647 if (value && value->id == CSSValueSpan) {
4648 hasSeenSpanKeyword = true;
4649 m_valueList->next();
4651 } else if (value->id == CSSValueSpan) {
4652 hasSeenSpanKeyword = true;
4653 if (m_valueList->next())
4654 parseIntegerOrStringFromGridPosition(numericValue, gridLineName);
4657 // Check that we have consumed all the value list. For shorthands, the parser will pass
4658 // the whole value list (including the opposite position).
4659 if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current()))
4662 // If we didn't parse anything, this is not a valid grid position.
4663 if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
4666 // Negative numbers are not allowed for span (but are for <integer>).
4667 if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
4670 RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
4671 if (hasSeenSpanKeyword)
4672 values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
4674 values->append(numericValue.release());
4676 values->append(gridLineName.release());
4677 ASSERT(values->length());
4678 return values.release();
4681 static PassRefPtr<CSSValue> gridMissingGridPositionValue(CSSValue* value)
4683 if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isString())
4686 return cssValuePool().createIdentifierValue(CSSValueAuto);
4689 bool BisonCSSParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
4691 ShorthandScope scope(this, shorthandId);
4692 const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
4693 ASSERT(shorthand.length() == 2);
4695 RefPtr<CSSValue> startValue = parseGridPosition();
4699 RefPtr<CSSValue> endValue;
4700 if (m_valueList->current()) {
4701 if (!isForwardSlashOperator(m_valueList->current()))
4704 if (!m_valueList->next())
4707 endValue = parseGridPosition();
4708 if (!endValue || m_valueList->current())
4711 endValue = gridMissingGridPositionValue(startValue.get());
4714 addProperty(shorthand.properties()[0], startValue, important);
4715 addProperty(shorthand.properties()[1], endValue, important);
4719 bool BisonCSSParser::parseGridAreaShorthand(bool important)
4721 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4723 ShorthandScope scope(this, CSSPropertyGridArea);
4724 const StylePropertyShorthand& shorthand = gridAreaShorthand();
4725 ASSERT_UNUSED(shorthand, shorthand.length() == 4);
4727 RefPtr<CSSValue> rowStartValue = parseGridPosition();
4731 RefPtr<CSSValue> columnStartValue;
4732 if (!parseSingleGridAreaLonghand(columnStartValue))
4735 RefPtr<CSSValue> rowEndValue;
4736 if (!parseSingleGridAreaLonghand(rowEndValue))
4739 RefPtr<CSSValue> columnEndValue;
4740 if (!parseSingleGridAreaLonghand(columnEndValue))
4743 if (!columnStartValue)
4744 columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
4747 rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
4749 if (!columnEndValue)
4750 columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
4752 addProperty(CSSPropertyGridRowStart, rowStartValue, important);
4753 addProperty(CSSPropertyGridColumnStart, columnStartValue, important);
4754 addProperty(CSSPropertyGridRowEnd, rowEndValue, important);
4755 addProperty(CSSPropertyGridColumnEnd, columnEndValue, important);
4759 bool BisonCSSParser::parseSingleGridAreaLonghand(RefPtr<CSSValue>& property)
4761 if (!m_valueList->current())
4764 if (!isForwardSlashOperator(m_valueList->current()))
4767 if (!m_valueList->next())
4770 property = parseGridPosition();
4774 void BisonCSSParser::parseGridLineNames(CSSParserValueList* parserValueList, CSSValueList& valueList)
4776 ASSERT(parserValueList->current() && parserValueList->current()->unit == CSSParserValue::ValueList);
4778 CSSParserValueList* identList = parserValueList->current()->valueList;
4779 if (!identList->size()) {
4780 parserValueList->next();
4784 RefPtr<CSSGridLineNamesValue> lineNames = CSSGridLineNamesValue::create();
4785 while (CSSParserValue* identValue = identList->current()) {
4786 ASSERT(identValue->unit == CSSPrimitiveValue::CSS_IDENT);
4787 RefPtr<CSSPrimitiveValue> lineName = createPrimitiveStringValue(identValue);
4788 lineNames->append(lineName.release());
4791 valueList.append(lineNames.release());
4793 parserValueList->next();
4796 bool BisonCSSParser::parseGridTrackList(CSSPropertyID propId, bool important)
4798 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4800 CSSParserValue* value = m_valueList->current();
4801 if (value->id == CSSValueNone) {
4802 if (m_valueList->next())
4805 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
4809 RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
4810 // Handle leading <ident>*.
4811 value = m_valueList->current();
4812 if (value && value->unit == CSSParserValue::ValueList)
4813 parseGridLineNames(m_valueList.get(), *values);
4815 bool seenTrackSizeOrRepeatFunction = false;
4816 while (CSSParserValue* currentValue = m_valueList->current()) {
4817 if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "repeat(")) {
4818 if (!parseGridTrackRepeatFunction(*values))
4820 seenTrackSizeOrRepeatFunction = true;
4822 RefPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
4825 values->append(value);
4826 seenTrackSizeOrRepeatFunction = true;
4828 // This will handle the trailing <ident>* in the grammar.
4829 value = m_valueList->current();
4830 if (value && value->unit == CSSParserValue::ValueList)
4831 parseGridLineNames(m_valueList.get(), *values);
4834 // We should have found a <track-size> or else it is not a valid <track-list>
4835 if (!seenTrackSizeOrRepeatFunction)
4838 addProperty(propId, values.release(), important);
4842 bool BisonCSSParser::parseGridTrackRepeatFunction(CSSValueList& list)
4844 CSSParserValueList* arguments = m_valueList->current()->function->args.get();
4845 if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1)))
4848 ASSERT_WITH_SECURITY_IMPLICATION(arguments->valueAt(0)->fValue > 0);
4849 size_t repetitions = arguments->valueAt(0)->fValue;
4850 RefPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
4851 arguments->next(); // Skip the repetition count.
4852 arguments->next(); // Skip the comma.
4854 // Handle leading <ident>*.
4855 CSSParserValue* currentValue = arguments->current();
4856 if (currentValue && currentValue->unit == CSSParserValue::ValueList)
4857 parseGridLineNames(arguments, *repeatedValues);
4859 while (arguments->current()) {
4860 RefPtr<CSSValue> trackSize = parseGridTrackSize(*arguments);
4864 repeatedValues->append(trackSize);
4866 // This takes care of any trailing <ident>* in the grammar.
4867 currentValue = arguments->current();
4868 if (currentValue && currentValue->unit == CSSParserValue::ValueList)
4869 parseGridLineNames(arguments, *repeatedValues);
4872 for (size_t i = 0; i < repetitions; ++i) {
4873 for (size_t j = 0; j < repeatedValues->length(); ++j)
4874 list.append(repeatedValues->itemWithoutBoundsCheck(j));
4877 // parseGridTrackSize iterated over the repeat arguments, move to the next value.
4878 m_valueList->next();
4882 PassRefPtr<CSSValue> BisonCSSParser::parseGridTrackSize(CSSParserValueList& inputList)
4884 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4886 CSSParserValue* currentValue = inputList.current();
4889 if (currentValue->id == CSSValueAuto)
4890 return cssValuePool().createIdentifierValue(CSSValueAuto);
4892 if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax(")) {
4893 // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
4894 CSSParserValueList* arguments = currentValue->function->args.get();
4895 if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
4898 RefPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0));
4899 if (!minTrackBreadth)
4902 RefPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2));
4903 if (!maxTrackBreadth)
4906 RefPtr<CSSValueList> parsedArguments = CSSValueList::createCommaSeparated();
4907 parsedArguments->append(minTrackBreadth);
4908 parsedArguments->append(maxTrackBreadth);
4909 return CSSFunctionValue::create("minmax(", parsedArguments);
4912 return parseGridBreadth(currentValue);
4915 PassRefPtr<CSSPrimitiveValue> BisonCSSParser::parseGridBreadth(CSSParserValue* currentValue)
4917 if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMaxContent)
4918 return cssValuePool().createIdentifierValue(currentValue->id);
4920 if (currentValue->unit == CSSPrimitiveValue::CSS_FR) {
4921 double flexValue = currentValue->fValue;
4923 // Fractional unit is a non-negative dimension.
4927 return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR);
4930 if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
4933 return createPrimitiveNumericValue(currentValue);
4936 PassRefPtr<CSSValue> BisonCSSParser::parseGridTemplate()
4938 NamedGridAreaMap gridAreaMap;
4939 size_t rowCount = 0;
4940 size_t columnCount = 0;
4942 while (CSSParserValue* currentValue = m_valueList->current()) {
4943 if (currentValue->unit != CSSPrimitiveValue::CSS_STRING)
4946 String gridRowNames = currentValue->string;
4947 if (!gridRowNames.length())
4950 Vector<String> columnNames;
4951 gridRowNames.split(' ', columnNames);
4954 columnCount = columnNames.size();
4955 ASSERT(columnCount);
4956 } else if (columnCount != columnNames.size()) {
4957 // The declaration is invalid is all the rows don't have the number of columns.
4961 for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
4962 const String& gridAreaName = columnNames[currentCol];
4964 // Unamed areas are always valid (we consider them to be 1x1).
4965 if (gridAreaName == ".")
4968 // We handle several grid areas with the same name at once to simplify the validation code.
4969 size_t lookAheadCol;
4970 for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++lookAheadCol) {
4971 if (columnNames[lookAheadCol + 1] != gridAreaName)
4975 NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
4976 if (gridAreaIt == gridAreaMap.end()) {
4977 gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowCount), GridSpan(currentCol, lookAheadCol)));
4979 GridCoordinate& gridCoordinate = gridAreaIt->value;
4981 // The following checks test that the grid area is a single filled-in rectangle.
4982 // 1. The new row is adjacent to the previously parsed row.
4983 if (rowCount != gridCoordinate.rows.initialPositionIndex + 1)
4986 // 2. The new area starts at the same position as the previously parsed area.
4987 if (currentCol != gridCoordinate.columns.initialPositionIndex)
4990 // 3. The new area ends at the same position as the previously parsed area.
4991 if (lookAheadCol != gridCoordinate.columns.finalPositionIndex)
4994 ++gridCoordinate.rows.finalPositionIndex;
4996 currentCol = lookAheadCol;
5000 m_valueList->next();
5003 if (!rowCount || !columnCount)
5006 return CSSGridTemplateValue::create(gridAreaMap, rowCount, columnCount);
5009 PassRefPtr<CSSValue> BisonCSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
5011 unsigned numArgs = args->size();
5012 if (counters && numArgs != 3 && numArgs != 5)
5014 if (!counters && numArgs != 1 && numArgs != 3)
5017 CSSParserValue* i = args->current();
5018 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
5020 RefPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i);
5022 RefPtr<CSSPrimitiveValue> separator;
5024 separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING);
5027 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
5031 if (i->unit != CSSPrimitiveValue::CSS_STRING)
5034 separator = createPrimitiveStringValue(i);
5037 RefPtr<CSSPrimitiveValue> listStyle;
5039 if (!i) // Make the list style default decimal
5040 listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
5042 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
5046 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
5049 CSSValueID listStyleID = CSSValueInvalid;
5050 if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha))
5051 listStyleID = i->id;
5055 listStyle = cssValuePool().createIdentifierValue(listStyleID);
5058 return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
5061 bool BisonCSSParser::parseClipShape(CSSPropertyID propId, bool important)
5063 CSSParserValue* value = m_valueList->current();
5064 CSSParserValueList* args = value->function->args.get();
5066 if (!equalIgnoringCase(value->function->name, "rect(") || !args)
5069 // rect(t, r, b, l) || rect(t r b l)
5070 if (args->size() != 4 && args->size() != 7)
5072 RefPtr<Rect> rect = Rect::create();
5075 CSSParserValue* a = args->current();
5077 valid = a->id == CSSValueAuto || validUnit(a, FLength);
5080 RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
5081 cssValuePool().createIdentifierValue(CSSValueAuto) :
5082 createPrimitiveNumericValue(a);
5084 rect->setTop(length);
5086 rect->setRight(length);
5088 rect->setBottom(length);
5090 rect->setLeft(length);
5092 if (a && args->size() == 7) {
5093 if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
5103 addProperty(propId, cssValuePool().createValue(rect.release()), important);
5104 m_valueList->next();
5110 static bool isItemPositionKeyword(CSSValueID id)
5112 return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
5113 || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
5114 || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight;
5117 bool BisonCSSParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important)
5119 // auto | baseline | stretch | [<item-position> && <overflow-position>? ]
5120 // <item-position> = center | start | end | self-start | self-end | flex-start | flex-end | left | right;
5121 // <overflow-position> = true | safe
5123 CSSParserValue* value = m_valueList->current();
5125 if (value->id == CSSValueAuto || value->id == CSSValueBaseline || value->id == CSSValueStretch) {
5126 if (m_valueList->next())
5129 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
5133 RefPtr<CSSPrimitiveValue> position = 0;
5134 RefPtr<CSSPrimitiveValue> overflowAlignmentKeyword = 0;
5135 if (isItemPositionKeyword(value->id)) {
5136 position = cssValuePool().createIdentifierValue(value->id);
5137 value = m_valueList->next();
5139 if (value->id == CSSValueTrue || value->id == CSSValueSafe)
5140 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
5144 } else if (value->id == CSSValueTrue || value->id == CSSValueSafe) {
5145 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
5146 value = m_valueList->next();
5148 if (isItemPositionKeyword(value->id))
5149 position = cssValuePool().createIdentifierValue(value->id);
5157 if (m_valueList->next())
5161 if (overflowAlignmentKeyword)
5162 addProperty(propId, createPrimitiveValuePair(position, overflowAlignmentKeyword), important);
5164 addProperty(propId, position.release(), important);
5169 PassRefPtr<CSSBasicShape> BisonCSSParser::parseBasicShapeRectangle(CSSParserValueList* args)
5173 // rect(x, y, width, height, [[rx], ry])
5174 if (args->size() != 7 && args->size() != 9 && args->size() != 11)
5177 RefPtr<CSSBasicShapeRectangle> shape = CSSBasicShapeRectangle::create();
5179 unsigned argumentNumber = 0;
5180 CSSParserValue* argument = args->current();
5182 Units unitFlags = FLength | FPercent;
5183 if (argumentNumber > 1) {
5184 // Arguments width, height, rx, and ry cannot be negative.
5185 unitFlags = unitFlags | FNonNeg;
5187 if (!validUnit(argument, unitFlags))
5190 RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5191 ASSERT(argumentNumber < 6);
5192 switch (argumentNumber) {
5194 shape->setX(length);
5197 shape->setY(length);
5200 shape->setWidth(length);
5203 shape->setHeight(length);
5206 shape->setRadiusX(length);
5209 shape->setRadiusY(length);
5212 argument = args->next();
5214 if (!isComma(argument))
5217 argument = args->next();
5222 if (argumentNumber < 4)
5227 PassRefPtr<CSSBasicShape> BisonCSSParser::parseBasicShapeInsetRectangle(CSSParserValueList* args)
5231 // inset-rectangle(top, right, bottom, left, [[rx], ry])
5232 if (args->size() != 7 && args->size() != 9 && args->size() != 11)
5235 RefPtr<CSSBasicShapeInsetRectangle> shape = CSSBasicShapeInsetRectangle::create();
5237 unsigned argumentNumber = 0;
5238 CSSParserValue* argument = args->current();
5240 Units unitFlags = FLength | FPercent | FNonNeg;
5241 if (!validUnit(argument, unitFlags))
5244 RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5245 ASSERT(argumentNumber < 6);
5246 switch (argumentNumber) {
5248 shape->setTop(length);
5251 shape->setRight(length);
5254 shape->setBottom(length);
5257 shape->setLeft(length);
5260 shape->setRadiusX(length);
5263 shape->setRadiusY(length);
5266 argument = args->next();
5268 if (!isComma(argument))
5271 argument = args->next();
5276 if (argumentNumber < 4)
5281 PassRefPtr<CSSPrimitiveValue> BisonCSSParser::parseShapeRadius(CSSParserValue* value)
5283 if (value->id == CSSValueClosestSide || value->id == CSSValueFarthestSide)
5284 return cssValuePool().createIdentifierValue(value->id);
5286 if (!validUnit(value, FLength | FPercent | FNonNeg))
5289 return createPrimitiveNumericValue(value);
5292 PassRefPtr<CSSBasicShape> BisonCSSParser::parseBasicShapeCircle(CSSParserValueList* args)
5297 // circle(radius at <position>
5298 // circle(at <position>)
5299 // where position defines centerX and centerY using a CSS <position> data type.
5300 RefPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
5302 for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
5303 // The call to parseFillPosition below should consume all of the
5304 // arguments except the first two. Thus, and index greater than one
5305 // indicates an invalid production.
5306 if (args->currentIndex() > 1)
5309 if (!args->currentIndex() && argument->id != CSSValueAt) {
5310 if (RefPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
5311 shape->setRadius(radius);
5318 if (argument->id == CSSValueAt) {
5319 RefPtr<CSSValue> centerX;
5320 RefPtr<CSSValue> centerY;
5321 args->next(); // set list to start of position center
5322 parseFillPosition(args, centerX, centerY);
5323 if (centerX && centerY) {
5324 ASSERT(centerX->isPrimitiveValue());
5325 ASSERT(centerY->isPrimitiveValue());
5326 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
5327 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
5339 PassRefPtr<CSSBasicShape> BisonCSSParser::parseDeprecatedBasicShapeCircle(CSSParserValueList* args)
5343 // circle(centerX, centerY, radius)
5344 if (args->size() != 5)
5347 RefPtr<CSSDeprecatedBasicShapeCircle> shape = CSSDeprecatedBasicShapeCircle::create();
5349 unsigned argumentNumber = 0;
5350 CSSParserValue* argument = args->current();
5352 Units unitFlags = FLength | FPercent;
5353 if (argumentNumber == 2) {
5354 // Argument radius cannot be negative.
5355 unitFlags = unitFlags | FNonNeg;
5358 if (!validUnit(argument, unitFlags))
5361 RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5362 ASSERT(argumentNumber < 3);
5363 switch (argumentNumber) {
5365 shape->setCenterX(length);
5368 shape->setCenterY(length);
5371 shape->setRadius(length);
5375 argument = args->next();
5377 if (!isComma(argument))
5379 argument = args->next();
5384 if (argumentNumber < 3)
5389 PassRefPtr<CSSBasicShape> BisonCSSParser::parseBasicShapeEllipse(CSSParserValueList* args)
5394 // ellipse(radiusX at <position>
5395 // ellipse(radiusX radiusY)
5396 // ellipse(radiusX radiusY at <position>
5397 // ellipse(at <position>)
5398 // where position defines centerX and centerY using a CSS <position> data type.
5399 RefPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
5401 for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
5402 // The call to parseFillPosition below should consume all of the
5403 // arguments except the first three. Thus, an index greater than two
5404 // indicates an invalid production.
5405 if (args->currentIndex() > 2)
5408 if (args->currentIndex() < 2 && argument->id != CSSValueAt) {
5409 if (RefPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
5410 if (!shape->radiusX())
5411 shape->setRadiusX(radius);
5413 shape->setRadiusY(radius);
5420 if (argument->id != CSSValueAt)
5422 RefPtr<CSSValue> centerX;
5423 RefPtr<CSSValue> centerY;
5424 args->next(); // set list to start of position center
5425 parseFillPosition(args, centerX, centerY);
5426 if (!centerX || !centerY)
5429 ASSERT(centerX->isPrimitiveValue());
5430 ASSERT(centerY->isPrimitiveValue());
5431 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
5432 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
5438 PassRefPtr<CSSBasicShape> BisonCSSParser::parseDeprecatedBasicShapeEllipse(CSSParserValueList* args)
5442 // ellipse(centerX, centerY, radiusX, radiusY)
5443 if (args->size() != 7)
5446 RefPtr<CSSDeprecatedBasicShapeEllipse> shape = CSSDeprecatedBasicShapeEllipse::create();
5447 unsigned argumentNumber = 0;
5448 CSSParserValue* argument = args->current();
5450 Units unitFlags = FLength | FPercent;
5451 if (argumentNumber > 1) {
5452 // Arguments radiusX and radiusY cannot be negative.
5453 unitFlags = unitFlags | FNonNeg;
5455 if (!validUnit(argument, unitFlags))
5458 RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5459 ASSERT(argumentNumber < 4);
5460 switch (argumentNumber) {
5462 shape->setCenterX(length);
5465 shape->setCenterY(length);
5468 shape->setRadiusX(length);
5471 shape->setRadiusY(length);
5475 argument = args->next();
5477 if (!isComma(argument))
5479 argument = args->next();
5484 if (argumentNumber < 4)
5489 PassRefPtr<CSSBasicShape> BisonCSSParser::parseBasicShapePolygon(CSSParserValueList* args)
5493 unsigned size = args->size();
5497 RefPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
5499 CSSParserValue* argument = args->current();
5500 if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
5501 shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
5503 if (!isComma(args->next()))
5506 argument = args->next();
5510 // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one
5511 if (!size || (size % 3) - 2)
5514 CSSParserValue* argumentX = argument;
5516 if (!validUnit(argumentX, FLength | FPercent))
5519 CSSParserValue* argumentY = args->next();
5520 if (!argumentY || !validUnit(argumentY, FLength | FPercent))
5523 RefPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX);
5524 RefPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY);
5526 shape->appendPoint(xLength.release(), yLength.release());
5528 CSSParserValue* commaOrNull = args->next();
5531 else if (!isComma(commaOrNull))
5534 argumentX = args->next();
5540 static bool isBoxValue(CSSValueID valueId)
5543 case CSSValueContentBox:
5544 case CSSValuePaddingBox:
5545 case CSSValueBorderBox:
5546 case CSSValueMarginBox:
5555 // FIXME This function is temporary to allow for an orderly transition between
5556 // the new CSS Shapes circle and ellipse syntax. It will be removed when the
5557 // old syntax is removed.
5558 static bool isDeprecatedBasicShape(CSSParserValueList* args)
5560 for (unsigned i = args->currentIndex(); i < args->size(); ++i) {
5561 CSSParserValue* value = args->valueAt(i);
5569 PassRefPtr<CSSValue> BisonCSSParser::parseShapeProperty(CSSPropertyID propId)
5571 if (!RuntimeEnabledFeatures::cssShapesEnabled())
5574 CSSParserValue* value = m_valueList->current();
5575 CSSValueID valueId = value->id;
5576 RefPtr<CSSPrimitiveValue> boxValue;
5577 RefPtr<CSSPrimitiveValue> shapeValue;
5579 if (valueId == CSSValueNone
5580 || (valueId == CSSValueOutsideShape && propId == CSSPropertyShapeInside)) {
5581 RefPtr<CSSPrimitiveValue> keywordValue = parseValidPrimitive(valueId, value);
5582 m_valueList->next();
5583 return keywordValue.release();
5586 RefPtr<CSSValue> imageValue;
5587 if (valueId != CSSValueNone && parseFillImage(m_valueList.get(), imageValue)) {
5588 m_valueList->next();
5589 return imageValue.release();
5592 if (value->unit == CSSParserValue::Function) {
5593 shapeValue = parseBasicShape();
5596 } else if (isBoxValue(valueId)) {
5597 boxValue = parseValidPrimitive(valueId, value);
5598 m_valueList->next();
5603 ASSERT(shapeValue || boxValue);
5604 value = m_valueList->current();
5607 valueId = value->id;
5608 if (boxValue && value->unit == CSSParserValue::Function) {
5609 shapeValue = parseBasicShape();
5612 } else if (shapeValue && isBoxValue(valueId)) {
5613 boxValue = parseValidPrimitive(valueId, value);
5614 m_valueList->next();
5619 ASSERT(shapeValue && boxValue);
5620 shapeValue->getShapeValue()->setLayoutBox(boxValue.release());
5624 return shapeValue.release();
5625 return boxValue.release();
5628 PassRefPtr<CSSPrimitiveValue> BisonCSSParser::parseBasicShape()
5630 CSSParserValue* value = m_valueList->current();
5631 ASSERT(value->unit == CSSParserValue::Function);
5632 CSSParserValueList* args = value->function->args.get();
5637 RefPtr<CSSBasicShape> shape;
5638 if (equalIgnoringCase(value->function->name, "rectangle("))
5639 shape = parseBasicShapeRectangle(args);
5640 else if (equalIgnoringCase(value->function->name, "circle("))
5641 if (isDeprecatedBasicShape(args))
5642 shape = parseDeprecatedBasicShapeCircle(args);
5644 shape = parseBasicShapeCircle(args);
5645 else if (equalIgnoringCase(value->function->name, "ellipse("))
5646 if (isDeprecatedBasicShape(args))
5647 shape = parseDeprecatedBasicShapeEllipse(args);
5649 shape = parseBasicShapeEllipse(args);
5650 else if (equalIgnoringCase(value->function->name, "polygon("))
5651 shape = parseBasicShapePolygon(args);
5652 else if (equalIgnoringCase(value->function->name, "inset-rectangle("))
5653 shape = parseBasicShapeInsetRectangle(args);
5658 m_valueList->next();
5659 return cssValuePool().createValue(shape.release());
5662 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
5663 bool BisonCSSParser::parseFont(bool important)
5665 // Let's check if there is an inherit or initial somewhere in the shorthand.
5666 for (unsigned i = 0; i < m_valueList->size(); ++i) {
5667 if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial)
5671 ShorthandScope scope(this, CSSPropertyFont);
5672 // Optional font-style, font-variant and font-weight.
5673 bool fontStyleParsed = false;
5674 bool fontVariantParsed = false;
5675 bool fontWeightParsed = false;
5676 CSSParserValue* value;
5677 while ((value = m_valueList->current())) {
5678 if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
5679 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
5680 fontStyleParsed = true;
5681 } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
5682 // Font variant in the shorthand is particular, it only accepts normal or small-caps.
5683 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important);
5684 fontVariantParsed = true;
5685 } else if (!fontWeightParsed && parseFontWeight(important))
5686 fontWeightParsed = true;
5689 m_valueList->next();
5695 if (!fontStyleParsed)
5696 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5697 if (!fontVariantParsed)
5698 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5699 if (!fontWeightParsed)
5700 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5702 // Now a font size _must_ come.
5703 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
5704 if (!parseFontSize(important))
5707 value = m_valueList->current();
5711 if (isForwardSlashOperator(value)) {
5712 // The line-height property.
5713 value = m_valueList->next();
5716 if (!parseLineHeight(important))
5719 addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5721 // Font family must come now.
5722 RefPtr<CSSValue> parsedFamilyValue = parseFontFamily();
5723 if (!parsedFamilyValue)
5726 addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
5728 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
5729 // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
5730 // but we don't seem to support them at the moment. They should also be added here once implemented.
5731 if (m_valueList->current())
5737 class FontFamilyValueBuilder {
5739 FontFamilyValueBuilder(CSSValueList* list)
5744 void add(const CSSParserString& string)
5746 if (!m_builder.isEmpty())
5747 m_builder.append(' ');
5749 if (string.is8Bit()) {
5750 m_builder.append(string.characters8(), string.length());
5754 m_builder.append(string.characters16(), string.length());
5759 if (m_builder.isEmpty())
5761 m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString()));
5766 StringBuilder m_builder;
5767 CSSValueList* m_list;
5770 PassRefPtr<CSSValueList> BisonCSSParser::parseFontFamily()
5772 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
5773 CSSParserValue* value = m_valueList->current();
5775 FontFamilyValueBuilder familyBuilder(list.get());
5776 bool inFamily = false;
5779 CSSParserValue* nextValue = m_valueList->next();
5780 bool nextValBreaksFont = !nextValue ||
5781 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
5782 bool nextValIsFontName = nextValue &&
5783 ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
5784 (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
5786 bool valueIsKeyword = value->id == CSSValueInitial || value->id == CSSValueInherit || value->id == CSSValueDefault;
5787 if (valueIsKeyword && !inFamily) {
5788 if (nextValBreaksFont)
5789 value = m_valueList->next();
5790 else if (nextValIsFontName)
5795 if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
5797 familyBuilder.add(value->string);
5798 else if (nextValBreaksFont || !nextValIsFontName)
5799 list->append(cssValuePool().createIdentifierValue(value->id));
5801 familyBuilder.commit();
5802 familyBuilder.add(value->string);
5805 } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
5806 // Strings never share in a family name.
5808 familyBuilder.commit();
5809 list->append(cssValuePool().createFontFamilyValue(value->string));
5810 } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
5812 familyBuilder.add(value->string);
5813 else if (nextValBreaksFont || !nextValIsFontName)
5814 list->append(cssValuePool().createFontFamilyValue(value->string));
5816 familyBuilder.commit();
5817 familyBuilder.add(value->string);
5827 if (nextValBreaksFont) {
5828 value = m_valueList->next();
5829 familyBuilder.commit();
5832 else if (nextValIsFontName)
5837 familyBuilder.commit();
5839 if (!list->length())
5841 return list.release();
5844 bool BisonCSSParser::parseLineHeight(bool important)
5846 CSSParserValue* value = m_valueList->current();
5847 CSSValueID id = value->id;
5848 bool validPrimitive = false;
5849 // normal | <number> | <length> | <percentage> | inherit
5850 if (id == CSSValueNormal)
5851 validPrimitive = true;
5853 validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
5854 if (validPrimitive && (!m_valueList->next() || inShorthand()))
5855 addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important);
5856 return validPrimitive;
5859 bool BisonCSSParser::parseFontSize(bool important)
5861 CSSParserValue* value = m_valueList->current();
5862 CSSValueID id = value->id;
5863 bool validPrimitive = false;
5864 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
5865 if (id >= CSSValueXxSmall && id <= CSSValueLarger)
5866 validPrimitive = true;
5868 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
5869 if (validPrimitive && (!m_valueList->next() || inShorthand()))
5870 addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important);
5871 return validPrimitive;
5874 bool BisonCSSParser::parseFontVariant(bool important)
5876 RefPtr<CSSValueList> values;
5877 if (m_valueList->size() > 1)
5878 values = CSSValueList::createCommaSeparated();
5879 CSSParserValue* val;
5880 bool expectComma = false;
5881 while ((val = m_valueList->current())) {
5882 RefPtr<CSSPrimitiveValue> parsedValue;
5885 if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
5886 parsedValue = cssValuePool().createIdentifierValue(val->id);
5887 else if (val->id == CSSValueAll && !values) {
5888 // 'all' is only allowed in @font-face and with no other values. Make a value list to
5889 // indicate that we are in the @font-face case.
5890 values = CSSValueList::createCommaSeparated();
5891 parsedValue = cssValuePool().createIdentifierValue(val->id);
5893 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
5894 expectComma = false;
5895 m_valueList->next();
5902 m_valueList->next();
5905 values->append(parsedValue.release());
5907 addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
5912 if (values && values->length()) {
5913 m_hasFontFaceOnlyValues = true;
5914 addProperty(CSSPropertyFontVariant, values.release(), important);
5921 bool BisonCSSParser::parseFontWeight(bool important)
5923 CSSParserValue* value = m_valueList->current();
5924 if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
5925 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important);
5928 if (validUnit(value, FInteger | FNonNeg, HTMLQuirksMode)) {
5929 int weight = static_cast<int>(value->fValue);
5930 if (!(weight % 100) && weight >= 100 && weight <= 900) {
5931 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1)), important);
5938 bool BisonCSSParser::parseFontFaceSrcURI(CSSValueList* valueList)
5940 RefPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string)));
5942 CSSParserValue* value = m_valueList->next();
5944 valueList->append(uriValue.release());
5947 if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
5948 m_valueList->next();
5949 valueList->append(uriValue.release());
5953 if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format("))
5956 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
5957 // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
5958 CSSParserValueList* args = value->function->args.get();
5959 if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
5961 uriValue->setFormat(args->current()->string);
5962 valueList->append(uriValue.release());
5963 value = m_valueList->next();
5964 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
5965 m_valueList->next();
5969 bool BisonCSSParser::parseFontFaceSrcLocal(CSSValueList* valueList)
5971 CSSParserValueList* args = m_valueList->current()->function->args.get();
5972 if (!args || !args->size())
5975 if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING)
5976 valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string));
5977 else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
5978 StringBuilder builder;
5979 for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) {
5980 if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
5982 if (!builder.isEmpty())
5983 builder.append(' ');
5984 builder.append(localValue->string);
5986 valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
5990 if (CSSParserValue* value = m_valueList->next()) {
5991 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
5992 m_valueList->next();
5997 bool BisonCSSParser::parseFontFaceSrc()
5999 RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
6001 while (CSSParserValue* value = m_valueList->current()) {
6002 if (value->unit == CSSPrimitiveValue::CSS_URI) {
6003 if (!parseFontFaceSrcURI(values.get()))
6005 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) {
6006 if (!parseFontFaceSrcLocal(values.get()))
6011 if (!values->length())
6014 addProperty(CSSPropertySrc, values.release(), m_important);
6015 m_valueList->next();
6019 bool BisonCSSParser::parseFontFaceUnicodeRange()
6021 RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
6022 bool failed = false;
6023 bool operatorExpected = false;
6024 for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
6025 if (operatorExpected) {
6026 if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
6031 if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
6036 String rangeString = m_valueList->current()->string;
6039 unsigned length = rangeString.length();
6047 while (i < length) {
6048 UChar c = rangeString[i];
6049 if (c == '-' || c == '?')
6052 if (c >= '0' && c <= '9')
6054 else if (c >= 'A' && c <= 'F')
6055 from += 10 + c - 'A';
6056 else if (c >= 'a' && c <= 'f')
6057 from += 10 + c - 'a';
6069 else if (rangeString[i] == '?') {
6071 while (i < length && rangeString[i] == '?') {
6078 to = from + span - 1;
6080 if (length < i + 2) {
6085 while (i < length) {
6086 UChar c = rangeString[i];
6088 if (c >= '0' && c <= '9')
6090 else if (c >= 'A' && c <= 'F')
6092 else if (c >= 'a' && c <= 'f')
6104 values->append(CSSUnicodeRangeValue::create(from, to));
6106 if (failed || !values->length())
6108 addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
6112 // Returns the number of characters which form a valid double
6113 // and are terminated by the given terminator character
6114 template <typename CharacterType>
6115 static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
6117 int length = end - string;
6121 bool decimalMarkSeen = false;
6122 int processedLength = 0;
6124 for (int i = 0; i < length; ++i) {
6125 if (string[i] == terminator) {
6126 processedLength = i;
6129 if (!isASCIIDigit(string[i])) {
6130 if (!decimalMarkSeen && string[i] == '.')
6131 decimalMarkSeen = true;
6137 if (decimalMarkSeen && processedLength == 1)
6140 return processedLength;
6143 // Returns the number of characters consumed for parsing a valid double
6144 // terminated by the given terminator character
6145 template <typename CharacterType>
6146 static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value)
6148 int length = checkForValidDouble(string, end, terminator);
6153 double localValue = 0;
6155 // The consumed characters here are guaranteed to be
6156 // ASCII digits with or without a decimal mark
6157 for (; position < length; ++position) {
6158 if (string[position] == '.')
6160 localValue = localValue * 10 + string[position] - '0';
6163 if (++position == length) {
6168 double fraction = 0;
6171 while (position < length && scale < MAX_SCALE) {
6172 fraction = fraction * 10 + string[position++] - '0';
6176 value = localValue + fraction / scale;
6180 template <typename CharacterType>
6181 static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
6183 const CharacterType* current = string;
6184 double localValue = 0;
6185 bool negative = false;
6186 while (current != end && isHTMLSpace<CharacterType>(*current))
6188 if (current != end && *current == '-') {
6192 if (current == end || !isASCIIDigit(*current))
6194 while (current != end && isASCIIDigit(*current)) {
6195 double newValue = localValue * 10 + *current++ - '0';
6196 if (newValue >= 255) {
6197 // Clamp values at 255.
6199 while (current != end && isASCIIDigit(*current))
6203 localValue = newValue;
6209 if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
6212 if (*current == '.') {
6213 // We already parsed the integral part, try to parse
6214 // the fraction part of the percentage value.
6215 double percentage = 0;
6216 int numCharactersParsed = parseDouble(current, end, '%', percentage);
6217 if (!numCharactersParsed)
6219 current += numCharactersParsed;
6220 if (*current != '%')
6222 localValue += percentage;
6225 if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
6228 if (*current == '%') {
6229 expect = CSSPrimitiveValue::CSS_PERCENTAGE;
6230 localValue = localValue / 100.0 * 256.0;
6231 // Clamp values at 255 for percentages over 100%
6232 if (localValue > 255)
6236 expect = CSSPrimitiveValue::CSS_NUMBER;
6238 while (current != end && isHTMLSpace<CharacterType>(*current))
6240 if (current == end || *current++ != terminator)
6242 // Clamp negative values at zero.
6243 value = negative ? 0 : static_cast<int>(localValue);
6248 template <typename CharacterType>
6249 static inline bool isTenthAlpha(const CharacterType* string, const int length)
6252 if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
6256 if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
6262 template <typename CharacterType>
6263 static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
6265 while (string != end && isHTMLSpace<CharacterType>(*string))
6268 bool negative = false;
6270 if (string != end && *string == '-') {
6277 int length = end - string;
6281 if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
6284 if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
6285 if (checkForValidDouble(string, end, terminator)) {
6286 value = negative ? 0 : 255;
6293 if (length == 2 && string[0] != '.') {
6294 value = !negative && string[0] == '1' ? 255 : 0;
6299 if (isTenthAlpha(string, length - 1)) {
6300 static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
6301 value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
6307 if (!parseDouble(string, end, terminator, alpha))
6309 value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
6314 template <typename CharacterType>
6315 static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
6319 return characters[4] == '('
6320 && isASCIIAlphaCaselessEqual(characters[0], 'r')
6321 && isASCIIAlphaCaselessEqual(characters[1], 'g')
6322 && isASCIIAlphaCaselessEqual(characters[2], 'b')
6323 && isASCIIAlphaCaselessEqual(characters[3], 'a');
6326 template <typename CharacterType>
6327 static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
6331 return characters[3] == '('
6332 && isASCIIAlphaCaselessEqual(characters[0], 'r')
6333 && isASCIIAlphaCaselessEqual(characters[1], 'g')
6334 && isASCIIAlphaCaselessEqual(characters[2], 'b');
6337 template <typename CharacterType>
6338 static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length , bool strict)
6340 CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
6342 if (!strict && length >= 3) {
6343 if (characters[0] == '#') {
6344 if (Color::parseHexColor(characters + 1, length - 1, rgb))
6347 if (Color::parseHexColor(characters, length, rgb))
6352 // Try rgba() syntax.
6353 if (mightBeRGBA(characters, length)) {
6354 const CharacterType* current = characters + 5;
6355 const CharacterType* end = characters + length;
6361 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
6363 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
6365 if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
6367 if (!parseAlphaValue(current, end, ')', alpha))
6371 rgb = makeRGBA(red, green, blue, alpha);
6375 // Try rgb() syntax.
6376 if (mightBeRGB(characters, length)) {
6377 const CharacterType* current = characters + 4;
6378 const CharacterType* end = characters + length;
6382 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
6384 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
6386 if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
6390 rgb = makeRGB(red, green, blue);
6397 template<typename StringType>
6398 bool BisonCSSParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict)
6400 unsigned length = name.length();
6407 parseResult = fastParseColorInternal(rgb, name.characters8(), length, strict);
6409 parseResult = fastParseColorInternal(rgb, name.characters16(), length, strict);
6414 // Try named colors.
6416 if (!tc.setNamedColor(name))
6422 inline double BisonCSSParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc)
6424 const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue;
6425 if (releaseCalc == ReleaseParsedCalcValue)
6426 m_parsedCalculation.release();
6430 bool BisonCSSParser::isCalculation(CSSParserValue* value)
6432 return (value->unit == CSSParserValue::Function)
6433 && (equalIgnoringCase(value->function->name, "calc(")
6434 || equalIgnoringCase(value->function->name, "-webkit-calc(")
6435 || equalIgnoringCase(value->function->name, "-webkit-min(")
6436 || equalIgnoringCase(value->function->name, "-webkit-max("));
6439 inline int BisonCSSParser::colorIntFromValue(CSSParserValue* v)
6443 if (m_parsedCalculation)
6444 isPercent = m_parsedCalculation->category() == CalcPercent;
6446 isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
6448 const double value = parsedDouble(v, ReleaseParsedCalcValue);
6456 return static_cast<int>(value * 256.0 / 100.0);
6462 return static_cast<int>(value);
6465 bool BisonCSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
6467 CSSParserValueList* args = value->function->args.get();
6468 CSSParserValue* v = args->current();
6469 Units unitType = FUnknown;
6470 // Get the first value and its type
6471 if (validUnit(v, FInteger, HTMLStandardMode))
6472 unitType = FInteger;
6473 else if (validUnit(v, FPercent, HTMLStandardMode))
6474 unitType = FPercent;
6478 colorArray[0] = colorIntFromValue(v);
6479 for (int i = 1; i < 3; i++) {
6481 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6484 if (!validUnit(v, unitType, HTMLStandardMode))
6486 colorArray[i] = colorIntFromValue(v);
6490 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6493 if (!validUnit(v, FNumber, HTMLStandardMode))
6495 const double value = parsedDouble(v, ReleaseParsedCalcValue);
6496 // Convert the floating pointer number of alpha to an integer in the range [0, 256),
6497 // with an equal distribution across all 256 values.
6498 colorArray[3] = static_cast<int>(max(0.0, min(1.0, value)) * nextafter(256.0, 0.0));
6503 // The CSS3 specification defines the format of a HSL color as
6504 // hsl(<number>, <percent>, <percent>)
6505 // and with alpha, the format is
6506 // hsla(<number>, <percent>, <percent>, <number>)
6507 // The first value, HUE, is in an angle with a value between 0 and 360
6508 bool BisonCSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
6510 CSSParserValueList* args = value->function->args.get();
6511 CSSParserValue* v = args->current();
6512 // Get the first value
6513 if (!validUnit(v, FNumber, HTMLStandardMode))
6515 // normalize the Hue value and change it to be between 0 and 1.0
6516 colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0;
6517 for (int i = 1; i < 3; i++) {
6519 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6522 if (!validUnit(v, FPercent, HTMLStandardMode))
6524 colorArray[i] = max(0.0, min(100.0, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0
6528 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6531 if (!validUnit(v, FNumber, HTMLStandardMode))
6533 colorArray[3] = max(0.0, min(1.0, parsedDouble(v, ReleaseParsedCalcValue)));
6538 PassRefPtr<CSSPrimitiveValue> BisonCSSParser::parseColor(CSSParserValue* value)
6540 RGBA32 c = Color::transparent;
6541 if (!parseColorFromValue(value ? value : m_valueList->current(), c))
6543 return cssValuePool().createColorValue(c);
6546 bool BisonCSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
6548 if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
6549 && value->fValue >= 0. && value->fValue < 1000000.) {
6550 String str = String::format("%06d", static_cast<int>((value->fValue+.5)));
6551 // FIXME: This should be strict parsing for SVG as well.
6552 if (!fastParseColor(c, str, !inQuirksMode()))
6554 } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
6555 value->unit == CSSPrimitiveValue::CSS_IDENT ||
6556 (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
6557 if (!fastParseColor(c, value->string, !inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
6559 } else if (value->unit == CSSParserValue::Function &&
6560 value->function->args != 0 &&
6561 value->function->args->size() == 5 /* rgb + two commas */ &&
6562 equalIgnoringCase(value->function->name, "rgb(")) {
6564 if (!parseColorParameters(value, colorValues, false))
6566 c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
6568 if (value->unit == CSSParserValue::Function &&
6569 value->function->args != 0 &&
6570 value->function->args->size() == 7 /* rgba + three commas */ &&
6571 equalIgnoringCase(value->function->name, "rgba(")) {
6573 if (!parseColorParameters(value, colorValues, true))
6575 c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
6576 } else if (value->unit == CSSParserValue::Function &&
6577 value->function->args != 0 &&
6578 value->function->args->size() == 5 /* hsl + two commas */ &&
6579 equalIgnoringCase(value->function->name, "hsl(")) {
6580 double colorValues[3];
6581 if (!parseHSLParameters(value, colorValues, false))
6583 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
6584 } else if (value->unit == CSSParserValue::Function &&
6585 value->function->args != 0 &&
6586 value->function->args->size() == 7 /* hsla + three commas */ &&
6587 equalIgnoringCase(value->function->name, "hsla(")) {
6588 double colorValues[4];
6589 if (!parseHSLParameters(value, colorValues, true))
6591 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
6599 // This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return)
6600 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
6601 struct ShadowParseContext {
6602 ShadowParseContext(CSSPropertyID prop, BisonCSSParser* parser)
6608 , allowSpread(false)
6610 , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
6615 bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
6619 // Handle the ,, case gracefully by doing nothing.
6620 if (x || y || blur || spread || color || style) {
6622 values = CSSValueList::createCommaSeparated();
6624 // Construct the current shadow value and add it to the list.
6625 values->append(CSSShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
6628 // Now reset for the next shadow value.
6641 allowSpread = false;
6642 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6645 void commitLength(CSSParserValue* v)
6647 RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
6656 } else if (allowY) {
6661 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6663 } else if (allowBlur) {
6664 blur = val.release();
6666 allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6667 } else if (allowSpread) {
6668 spread = val.release();
6669 allowSpread = false;
6673 void commitColor(PassRefPtr<CSSPrimitiveValue> val)
6682 allowSpread = false;
6683 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6687 void commitStyle(CSSParserValue* v)
6689 style = cssValuePool().createIdentifierValue(v->id);
6695 allowSpread = false;
6700 CSSPropertyID property;
6701 BisonCSSParser* m_parser;
6703 RefPtr<CSSValueList> values;
6704 RefPtr<CSSPrimitiveValue> x;
6705 RefPtr<CSSPrimitiveValue> y;
6706 RefPtr<CSSPrimitiveValue> blur;
6707 RefPtr<CSSPrimitiveValue> spread;
6708 RefPtr<CSSPrimitiveValue> style;
6709 RefPtr<CSSPrimitiveValue> color;
6716 bool allowStyle; // inset or not.
6720 PassRefPtr<CSSValueList> BisonCSSParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId)
6722 ShadowParseContext context(propId, this);
6723 CSSParserValue* val;
6724 while ((val = valueList->current())) {
6725 // Check for a comma break first.
6726 if (val->unit == CSSParserValue::Operator) {
6727 if (val->iValue != ',' || !context.allowBreak)
6728 // Other operators aren't legal or we aren't done with the current shadow
6729 // value. Treat as invalid.
6731 // The value is good. Commit it.
6732 context.commitValue();
6733 } else if (validUnit(val, FLength, HTMLStandardMode)) {
6734 // We required a length and didn't get one. Invalid.
6735 if (!context.allowLength())
6738 // Blur radius must be non-negative.
6739 if (context.allowBlur && !validUnit(val, FLength | FNonNeg, HTMLStandardMode))
6742 // A length is allowed here. Construct the value and add it.
6743 context.commitLength(val);
6744 } else if (val->id == CSSValueInset) {
6745 if (!context.allowStyle)
6748 context.commitStyle(val);
6750 // The only other type of value that's ok is a color value.
6751 RefPtr<CSSPrimitiveValue> parsedColor;
6752 bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu
6753 || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode())
6754 || val->id == CSSValueCurrentcolor);
6756 if (!context.allowColor)
6758 parsedColor = cssValuePool().createIdentifierValue(val->id);
6762 // It's not built-in. Try to parse it as a color.
6763 parsedColor = parseColor(val);
6765 if (!parsedColor || !context.allowColor)
6766 return 0; // This value is not a color or length and is invalid or
6767 // it is a color, but a color isn't allowed at this point.
6769 context.commitColor(parsedColor.release());
6775 if (context.allowBreak) {
6776 context.commitValue();
6777 if (context.values && context.values->length())
6778 return context.values.release();
6784 bool BisonCSSParser::parseReflect(CSSPropertyID propId, bool important)
6786 // box-reflect: <direction> <offset> <mask>
6788 // Direction comes first.
6789 CSSParserValue* val = m_valueList->current();
6790 RefPtr<CSSPrimitiveValue> direction;
6791 if (isVariableReference(val)) {
6792 direction = createPrimitiveVariableReferenceValue(val);
6799 direction = cssValuePool().createIdentifierValue(val->id);
6806 // The offset comes next.
6807 val = m_valueList->next();
6808 RefPtr<CSSPrimitiveValue> offset;
6810 offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6812 if (!validUnit(val, FLength | FPercent))
6814 offset = createPrimitiveNumericValue(val);
6817 // Now for the mask.
6818 RefPtr<CSSValue> mask;
6819 val = m_valueList->next();
6821 mask = parseBorderImage(propId);
6826 RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction.release(), offset.release(), mask.release());
6827 addProperty(propId, reflectValue.release(), important);
6828 m_valueList->next();
6832 bool BisonCSSParser::parseFlex(CSSParserValueList* args, bool important)
6834 if (!args || !args->size() || args->size() > 3)
6836 static const double unsetValue = -1;
6837 double flexGrow = unsetValue;
6838 double flexShrink = unsetValue;
6839 RefPtr<CSSPrimitiveValue> flexBasis;
6841 while (CSSParserValue* arg = args->current()) {
6842 if (validUnit(arg, FNumber | FNonNeg)) {
6843 if (flexGrow == unsetValue)
6844 flexGrow = arg->fValue;
6845 else if (flexShrink == unsetValue)
6846 flexShrink = arg->fValue;
6847 else if (!arg->fValue) {
6848 // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
6849 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6851 // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
6854 } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg)))
6855 flexBasis = parseValidPrimitive(arg->id, arg);
6857 // Not a valid arg for flex.
6863 if (flexGrow == unsetValue)
6865 if (flexShrink == unsetValue)
6868 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6870 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
6871 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
6872 addProperty(CSSPropertyFlexBasis, flexBasis, important);
6876 bool BisonCSSParser::parseObjectPosition(bool important)
6878 RefPtr<CSSValue> xValue;
6879 RefPtr<CSSValue> yValue;
6880 parseFillPosition(m_valueList.get(), xValue, yValue);
6881 if (!xValue || !yValue)
6884 CSSPropertyObjectPosition,
6885 createPrimitiveValuePair(toCSSPrimitiveValue(xValue.get()), toCSSPrimitiveValue(yValue.get()), Pair::KeepIdenticalValues),
6890 struct BorderImageParseContext {
6891 BorderImageParseContext()
6892 : m_canAdvance(false)
6893 , m_allowCommit(true)
6894 , m_allowImage(true)
6895 , m_allowImageSlice(true)
6896 , m_allowRepeat(true)
6897 , m_allowForwardSlashOperator(false)
6898 , m_requireWidth(false)
6899 , m_requireOutset(false)
6902 bool canAdvance() const { return m_canAdvance; }
6903 void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
6905 bool allowCommit() const { return m_allowCommit; }
6906 bool allowImage() const { return m_allowImage; }
6907 bool allowImageSlice() const { return m_allowImageSlice; }
6908 bool allowRepeat() const { return m_allowRepeat; }
6909 bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; }
6911 bool requireWidth() const { return m_requireWidth; }
6912 bool requireOutset() const { return m_requireOutset; }
6914 void commitImage(PassRefPtr<CSSValue> image)
6917 m_canAdvance = true;
6918 m_allowCommit = true;
6919 m_allowImage = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
6920 m_allowImageSlice = !m_imageSlice;
6921 m_allowRepeat = !m_repeat;
6923 void commitImageSlice(PassRefPtr<CSSBorderImageSliceValue> slice)
6925 m_imageSlice = slice;
6926 m_canAdvance = true;
6927 m_allowCommit = m_allowForwardSlashOperator = true;
6928 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
6929 m_allowImage = !m_image;
6930 m_allowRepeat = !m_repeat;
6932 void commitForwardSlashOperator()
6934 m_canAdvance = true;
6935 m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowForwardSlashOperator = false;
6936 if (!m_borderSlice) {
6937 m_requireWidth = true;
6938 m_requireOutset = false;
6940 m_requireOutset = true;
6941 m_requireWidth = false;
6944 void commitBorderWidth(PassRefPtr<CSSPrimitiveValue> slice)
6946 m_borderSlice = slice;
6947 m_canAdvance = true;
6948 m_allowCommit = m_allowForwardSlashOperator = true;
6949 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
6950 m_allowImage = !m_image;
6951 m_allowRepeat = !m_repeat;
6953 void commitBorderOutset(PassRefPtr<CSSPrimitiveValue> outset)
6956 m_canAdvance = true;
6957 m_allowCommit = true;
6958 m_allowImageSlice = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
6959 m_allowImage = !m_image;
6960 m_allowRepeat = !m_repeat;
6962 void commitRepeat(PassRefPtr<CSSValue> repeat)
6965 m_canAdvance = true;
6966 m_allowCommit = true;
6967 m_allowRepeat = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
6968 m_allowImageSlice = !m_imageSlice;
6969 m_allowImage = !m_image;
6972 PassRefPtr<CSSValue> commitCSSValue()
6974 return createBorderImageValue(m_image, m_imageSlice, m_borderSlice, m_outset, m_repeat);
6977 void commitMaskBoxImage(BisonCSSParser* parser, bool important)
6979 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSource, parser, m_image, important);
6980 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSlice, parser, m_imageSlice, important);
6981 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageWidth, parser, m_borderSlice, important);
6982 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageOutset, parser, m_outset, important);
6983 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageRepeat, parser, m_repeat, important);
6986 void commitBorderImage(BisonCSSParser* parser, bool important)
6988 commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
6989 commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice, important);
6990 commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice, important);
6991 commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset, important);
6992 commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important);
6995 void commitBorderImageProperty(CSSPropertyID propId, BisonCSSParser* parser, PassRefPtr<CSSValue> value, bool important)
6998 parser->addProperty(propId, value, important);
7000 parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true);
7007 bool m_allowImageSlice;
7009 bool m_allowForwardSlashOperator;
7011 bool m_requireWidth;
7012 bool m_requireOutset;
7014 RefPtr<CSSValue> m_image;
7015 RefPtr<CSSBorderImageSliceValue> m_imageSlice;
7016 RefPtr<CSSPrimitiveValue> m_borderSlice;
7017 RefPtr<CSSPrimitiveValue> m_outset;
7019 RefPtr<CSSValue> m_repeat;
7022 static bool buildBorderImageParseContext(BisonCSSParser& parser, CSSPropertyID propId, BorderImageParseContext& context)
7024 ShorthandScope scope(&parser, propId);
7025 while (CSSParserValue* val = parser.m_valueList->current()) {
7026 context.setCanAdvance(false);
7028 if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(val))
7029 context.commitForwardSlashOperator();
7031 if (!context.canAdvance() && context.allowImage()) {
7032 if (val->unit == CSSPrimitiveValue::CSS_URI) {
7033 context.commitImage(CSSImageValue::create(parser.m_context.completeURL(val->string)));
7034 } else if (isGeneratedImageValue(val)) {
7035 RefPtr<CSSValue> value;
7036 if (parser.parseGeneratedImage(parser.m_valueList.get(), value))
7037 context.commitImage(value.release());
7040 } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
7041 RefPtr<CSSValue> value = parser.parseImageSet(parser.m_valueList.get());
7043 context.commitImage(value.release());
7046 } else if (val->id == CSSValueNone)
7047 context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone));
7050 if (!context.canAdvance() && context.allowImageSlice()) {
7051 RefPtr<CSSBorderImageSliceValue> imageSlice;
7052 if (parser.parseBorderImageSlice(propId, imageSlice))
7053 context.commitImageSlice(imageSlice.release());
7056 if (!context.canAdvance() && context.allowRepeat()) {
7057 RefPtr<CSSValue> repeat;
7058 if (parser.parseBorderImageRepeat(repeat))
7059 context.commitRepeat(repeat.release());
7062 if (!context.canAdvance() && context.requireWidth()) {
7063 RefPtr<CSSPrimitiveValue> borderSlice;
7064 if (parser.parseBorderImageWidth(borderSlice))
7065 context.commitBorderWidth(borderSlice.release());
7068 if (!context.canAdvance() && context.requireOutset()) {
7069 RefPtr<CSSPrimitiveValue> borderOutset;
7070 if (parser.parseBorderImageOutset(borderOutset))
7071 context.commitBorderOutset(borderOutset.release());
7074 if (!context.canAdvance())
7077 parser.m_valueList->next();
7080 return context.allowCommit();
7083 bool BisonCSSParser::parseBorderImageShorthand(CSSPropertyID propId, bool important)
7085 BorderImageParseContext context;
7086 if (buildBorderImageParseContext(*this, propId, context)) {
7088 case CSSPropertyWebkitMaskBoxImage:
7089 context.commitMaskBoxImage(this, important);
7091 case CSSPropertyBorderImage:
7092 context.commitBorderImage(this, important);
7095 ASSERT_NOT_REACHED();
7102 PassRefPtr<CSSValue> BisonCSSParser::parseBorderImage(CSSPropertyID propId)
7104 BorderImageParseContext context;
7105 if (buildBorderImageParseContext(*this, propId, context)) {
7106 return context.commitCSSValue();
7111 static bool isBorderImageRepeatKeyword(int id)
7113 return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
7116 bool BisonCSSParser::parseBorderImageRepeat(RefPtr<CSSValue>& result)
7118 RefPtr<CSSPrimitiveValue> firstValue;
7119 RefPtr<CSSPrimitiveValue> secondValue;
7120 CSSParserValue* val = m_valueList->current();
7123 if (isBorderImageRepeatKeyword(val->id))
7124 firstValue = cssValuePool().createIdentifierValue(val->id);
7128 val = m_valueList->next();
7130 if (isBorderImageRepeatKeyword(val->id))
7131 secondValue = cssValuePool().createIdentifierValue(val->id);
7132 else if (!inShorthand()) {
7133 // If we're not parsing a shorthand then we are invalid.
7136 // We need to rewind the value list, so that when its advanced we'll
7137 // end up back at this value.
7138 m_valueList->previous();
7139 secondValue = firstValue;
7142 secondValue = firstValue;
7144 result = createPrimitiveValuePair(firstValue, secondValue);
7148 class BorderImageSliceParseContext {
7150 BorderImageSliceParseContext(BisonCSSParser* parser)
7152 , m_allowNumber(true)
7154 , m_allowFinalCommit(false)
7158 bool allowNumber() const { return m_allowNumber; }
7159 bool allowFill() const { return m_allowFill; }
7160 bool allowFinalCommit() const { return m_allowFinalCommit; }
7161 CSSPrimitiveValue* top() const { return m_top.get(); }
7163 void commitNumber(CSSParserValue* v)
7165 RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
7177 m_allowNumber = !m_left;
7178 m_allowFinalCommit = true;
7181 void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; }
7183 PassRefPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
7185 // We need to clone and repeat values for any omissions.
7199 // Now build a rect value to hold all four of our primitive values.
7200 RefPtr<Quad> quad = Quad::create();
7201 quad->setTop(m_top);
7202 quad->setRight(m_right);
7203 quad->setBottom(m_bottom);
7204 quad->setLeft(m_left);
7206 // Make our new border image value now.
7207 return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill);
7211 BisonCSSParser* m_parser;
7215 bool m_allowFinalCommit;
7217 RefPtr<CSSPrimitiveValue> m_top;
7218 RefPtr<CSSPrimitiveValue> m_right;
7219 RefPtr<CSSPrimitiveValue> m_bottom;
7220 RefPtr<CSSPrimitiveValue> m_left;
7225 bool BisonCSSParser::parseBorderImageSlice(CSSPropertyID propId, RefPtr<CSSBorderImageSliceValue>& result)
7227 BorderImageSliceParseContext context(this);
7228 CSSParserValue* val;
7229 while ((val = m_valueList->current())) {
7230 // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
7231 if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, HTMLStandardMode)) {
7232 context.commitNumber(val);
7233 } else if (context.allowFill() && val->id == CSSValueFill)
7234 context.commitFill();
7235 else if (!inShorthand()) {
7236 // If we're not parsing a shorthand then we are invalid.
7239 if (context.allowFinalCommit()) {
7240 // We're going to successfully parse, but we don't want to consume this token.
7241 m_valueList->previous();
7245 m_valueList->next();
7248 if (context.allowFinalCommit()) {
7249 // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
7250 // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
7251 if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
7252 context.commitFill();
7254 // Need to fully commit as a single value.
7255 result = context.commitBorderImageSlice();
7262 class BorderImageQuadParseContext {
7264 BorderImageQuadParseContext(BisonCSSParser* parser)
7266 , m_allowNumber(true)
7267 , m_allowFinalCommit(false)
7270 bool allowNumber() const { return m_allowNumber; }
7271 bool allowFinalCommit() const { return m_allowFinalCommit; }
7272 CSSPrimitiveValue* top() const { return m_top.get(); }
7274 void commitNumber(CSSParserValue* v)
7276 RefPtr<CSSPrimitiveValue> val;
7277 if (v->id == CSSValueAuto)
7278 val = cssValuePool().createIdentifierValue(v->id);
7280 val = m_parser->createPrimitiveNumericValue(v);
7293 m_allowNumber = !m_left;
7294 m_allowFinalCommit = true;
7297 void setAllowFinalCommit() { m_allowFinalCommit = true; }
7298 void setTop(PassRefPtr<CSSPrimitiveValue> val) { m_top = val; }
7300 PassRefPtr<CSSPrimitiveValue> commitBorderImageQuad()
7302 // We need to clone and repeat values for any omissions.
7316 // Now build a quad value to hold all four of our primitive values.
7317 RefPtr<Quad> quad = Quad::create();
7318 quad->setTop(m_top);
7319 quad->setRight(m_right);
7320 quad->setBottom(m_bottom);
7321 quad->setLeft(m_left);
7323 // Make our new value now.
7324 return cssValuePool().createValue(quad.release());
7328 BisonCSSParser* m_parser;
7331 bool m_allowFinalCommit;
7333 RefPtr<CSSPrimitiveValue> m_top;
7334 RefPtr<CSSPrimitiveValue> m_right;
7335 RefPtr<CSSPrimitiveValue> m_bottom;
7336 RefPtr<CSSPrimitiveValue> m_left;
7339 bool BisonCSSParser::parseBorderImageQuad(Units validUnits, RefPtr<CSSPrimitiveValue>& result)
7341 BorderImageQuadParseContext context(this);
7342 CSSParserValue* val;
7343 while ((val = m_valueList->current())) {
7344 if (context.allowNumber() && (validUnit(val, validUnits, HTMLStandardMode) || val->id == CSSValueAuto)) {
7345 context.commitNumber(val);
7346 } else if (!inShorthand()) {
7347 // If we're not parsing a shorthand then we are invalid.
7350 if (context.allowFinalCommit())
7351 m_valueList->previous(); // The shorthand loop will advance back to this point.
7354 m_valueList->next();
7357 if (context.allowFinalCommit()) {
7358 // Need to fully commit as a single value.
7359 result = context.commitBorderImageQuad();
7365 bool BisonCSSParser::parseBorderImageWidth(RefPtr<CSSPrimitiveValue>& result)
7367 return parseBorderImageQuad(FLength | FNumber | FNonNeg | FPercent, result);
7370 bool BisonCSSParser::parseBorderImageOutset(RefPtr<CSSPrimitiveValue>& result)
7372 return parseBorderImageQuad(FLength | FNumber | FNonNeg, result);
7375 static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4])
7381 radii[1] = radii[0];
7382 radii[2] = radii[0];
7384 radii[3] = radii[1];
7387 bool BisonCSSParser::parseBorderRadius(CSSPropertyID propId, bool important)
7389 unsigned num = m_valueList->size();
7393 ShorthandScope scope(this, propId);
7394 RefPtr<CSSPrimitiveValue> radii[2][4];
7396 unsigned indexAfterSlash = 0;
7397 for (unsigned i = 0; i < num; ++i) {
7398 CSSParserValue* value = m_valueList->valueAt(i);
7399 if (value->unit == CSSParserValue::Operator) {
7400 if (value->iValue != '/')
7403 if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
7406 indexAfterSlash = i + 1;
7407 completeBorderRadii(radii[0]);
7411 if (i - indexAfterSlash >= 4)
7414 if (!validUnit(value, FLength | FPercent | FNonNeg))
7417 RefPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
7419 if (!indexAfterSlash) {
7420 radii[0][i] = radius;
7422 // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
7423 if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
7424 indexAfterSlash = 1;
7425 completeBorderRadii(radii[0]);
7428 radii[1][i - indexAfterSlash] = radius.release();
7431 if (!indexAfterSlash) {
7432 completeBorderRadii(radii[0]);
7433 for (unsigned i = 0; i < 4; ++i)
7434 radii[1][i] = radii[0][i];
7436 completeBorderRadii(radii[1]);
7438 ImplicitScope implicitScope(this, PropertyImplicit);
7439 addProperty(CSSPropertyBorderTopLeftRadius, createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()), important);
7440 addProperty(CSSPropertyBorderTopRightRadius, createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()), important);
7441 addProperty(CSSPropertyBorderBottomRightRadius, createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()), important);
7442 addProperty(CSSPropertyBorderBottomLeftRadius, createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()), important);
7446 bool BisonCSSParser::parseAspectRatio(bool important)
7448 unsigned num = m_valueList->size();
7449 if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
7450 addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(CSSValueNone), important);
7457 CSSParserValue* lvalue = m_valueList->valueAt(0);
7458 CSSParserValue* op = m_valueList->valueAt(1);
7459 CSSParserValue* rvalue = m_valueList->valueAt(2);
7461 if (!isForwardSlashOperator(op))
7464 if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
7467 if (!lvalue->fValue || !rvalue->fValue)
7470 addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important);
7475 bool BisonCSSParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important)
7477 enum { ID, VAL } state = ID;
7479 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
7480 RefPtr<CSSPrimitiveValue> counterName;
7483 CSSParserValue* val = m_valueList->current();
7486 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
7487 counterName = createPrimitiveStringValue(val);
7489 m_valueList->next();
7494 int i = defaultValue;
7495 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
7496 i = clampToInteger(val->fValue);
7497 m_valueList->next();
7500 list->append(createPrimitiveValuePair(counterName.release(),
7501 cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER)));
7509 if (list->length() > 0) {
7510 addProperty(propId, list.release(), important);
7517 // This should go away once we drop support for -webkit-gradient
7518 static PassRefPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
7520 RefPtr<CSSPrimitiveValue> result;
7521 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
7522 if ((equalIgnoringCase(a, "left") && horizontal)
7523 || (equalIgnoringCase(a, "top") && !horizontal))
7524 result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
7525 else if ((equalIgnoringCase(a, "right") && horizontal)
7526 || (equalIgnoringCase(a, "bottom") && !horizontal))
7527 result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
7528 else if (equalIgnoringCase(a, "center"))
7529 result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
7530 } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7531 result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(a->unit));
7535 static bool parseDeprecatedGradientColorStop(BisonCSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
7537 if (a->unit != CSSParserValue::Function)
7540 if (!equalIgnoringCase(a->function->name, "from(") &&
7541 !equalIgnoringCase(a->function->name, "to(") &&
7542 !equalIgnoringCase(a->function->name, "color-stop("))
7545 CSSParserValueList* args = a->function->args.get();
7549 if (equalIgnoringCase(a->function->name, "from(")
7550 || equalIgnoringCase(a->function->name, "to(")) {
7551 // The "from" and "to" stops expect 1 argument.
7552 if (args->size() != 1)
7555 if (equalIgnoringCase(a->function->name, "from("))
7556 stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
7558 stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
7560 CSSValueID id = args->current()->id;
7561 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
7562 stop.m_color = cssValuePool().createIdentifierValue(id);
7564 stop.m_color = p->parseColor(args->current());
7569 // The "color-stop" function expects 3 arguments.
7570 if (equalIgnoringCase(a->function->name, "color-stop(")) {
7571 if (args->size() != 3)
7574 CSSParserValue* stopArg = args->current();
7575 if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7576 stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
7577 else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
7578 stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
7582 stopArg = args->next();
7583 if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
7586 stopArg = args->next();
7587 CSSValueID id = stopArg->id;
7588 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
7589 stop.m_color = cssValuePool().createIdentifierValue(id);
7591 stop.m_color = p->parseColor(stopArg);
7599 bool BisonCSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient)
7601 // Walk the arguments.
7602 CSSParserValueList* args = valueList->current()->function->args.get();
7603 if (!args || args->size() == 0)
7606 // The first argument is the gradient type. It is an identifier.
7607 CSSGradientType gradientType;
7608 CSSParserValue* a = args->current();
7609 if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
7611 if (equalIgnoringCase(a, "linear"))
7612 gradientType = CSSDeprecatedLinearGradient;
7613 else if (equalIgnoringCase(a, "radial"))
7614 gradientType = CSSDeprecatedRadialGradient;
7618 RefPtr<CSSGradientValue> result;
7619 switch (gradientType) {
7620 case CSSDeprecatedLinearGradient:
7621 result = CSSLinearGradientValue::create(NonRepeating, gradientType);
7623 case CSSDeprecatedRadialGradient:
7624 result = CSSRadialGradientValue::create(NonRepeating, gradientType);
7627 // The rest of the gradient types shouldn't appear here.
7628 ASSERT_NOT_REACHED();
7636 // Next comes the starting point for the gradient as an x y pair. There is no
7637 // comma between the x and the y values.
7638 // First X. It can be left, right, number or percent.
7642 RefPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
7645 result->setFirstX(point.release());
7647 // First Y. It can be top, bottom, number or percent.
7651 point = parseDeprecatedGradientPoint(a, false);
7654 result->setFirstY(point.release());
7656 // Comma after the first point.
7661 // For radial gradients only, we now expect a numeric radius.
7662 if (gradientType == CSSDeprecatedRadialGradient) {
7664 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
7666 toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
7668 // Comma after the first radius.
7674 // Next is the ending point for the gradient as an x, y pair.
7675 // Second X. It can be left, right, number or percent.
7679 point = parseDeprecatedGradientPoint(a, true);
7682 result->setSecondX(point.release());
7684 // Second Y. It can be top, bottom, number or percent.
7688 point = parseDeprecatedGradientPoint(a, false);
7691 result->setSecondY(point.release());
7693 // For radial gradients only, we now expect the second radius.
7694 if (gradientType == CSSDeprecatedRadialGradient) {
7695 // Comma after the second point.
7701 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
7703 toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
7706 // We now will accept any number of stops (0 or more).
7709 // Look for the comma before the next stop.
7713 // Now examine the stop itself.
7718 // The function name needs to be one of "from", "to", or "color-stop."
7719 CSSGradientColorStop stop;
7720 if (!parseDeprecatedGradientColorStop(this, a, stop))
7722 result->addStop(stop);
7728 gradient = result.release();
7732 static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
7734 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
7740 isHorizontal = true;
7743 case CSSValueBottom:
7744 isHorizontal = false;
7749 return cssValuePool().createIdentifierValue(a->id);
7752 static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(BisonCSSParser* p, CSSParserValue* value)
7754 CSSValueID id = value->id;
7755 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
7756 return cssValuePool().createIdentifierValue(id);
7758 return p->parseColor(value);
7761 bool BisonCSSParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7763 RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient);
7765 // Walk the arguments.
7766 CSSParserValueList* args = valueList->current()->function->args.get();
7767 if (!args || !args->size())
7770 CSSParserValue* a = args->current();
7774 bool expectComma = false;
7776 if (validUnit(a, FAngle, HTMLStandardMode)) {
7777 result->setAngle(createPrimitiveNumericValue(a));
7782 // Look one or two optional keywords that indicate a side or corner.
7783 RefPtr<CSSPrimitiveValue> startX, startY;
7785 RefPtr<CSSPrimitiveValue> location;
7786 bool isHorizontal = false;
7787 if ((location = valueFromSideKeyword(a, isHorizontal))) {
7793 if ((a = args->next())) {
7794 if ((location = valueFromSideKeyword(a, isHorizontal))) {
7812 if (!startX && !startY)
7813 startY = cssValuePool().createIdentifierValue(CSSValueTop);
7815 result->setFirstX(startX.release());
7816 result->setFirstY(startY.release());
7819 if (!parseGradientColorStops(args, result.get(), expectComma))
7822 if (!result->stopCount())
7825 gradient = result.release();
7829 bool BisonCSSParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7831 RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
7833 // Walk the arguments.
7834 CSSParserValueList* args = valueList->current()->function->args.get();
7835 if (!args || !args->size())
7838 CSSParserValue* a = args->current();
7842 bool expectComma = false;
7844 // Optional background-position
7845 RefPtr<CSSValue> centerX;
7846 RefPtr<CSSValue> centerY;
7847 // parse2ValuesFillPosition advances the args next pointer.
7848 parse2ValuesFillPosition(args, centerX, centerY);
7849 a = args->current();
7853 if (centerX || centerY) {
7863 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
7864 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
7865 // CSS3 radial gradients always share the same start and end point.
7866 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
7867 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
7869 RefPtr<CSSPrimitiveValue> shapeValue;
7870 RefPtr<CSSPrimitiveValue> sizeValue;
7872 // Optional shape and/or size in any order.
7873 for (int i = 0; i < 2; ++i) {
7874 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
7877 bool foundValue = false;
7879 case CSSValueCircle:
7880 case CSSValueEllipse:
7881 shapeValue = cssValuePool().createIdentifierValue(a->id);
7884 case CSSValueClosestSide:
7885 case CSSValueClosestCorner:
7886 case CSSValueFarthestSide:
7887 case CSSValueFarthestCorner:
7888 case CSSValueContain:
7890 sizeValue = cssValuePool().createIdentifierValue(a->id);
7906 result->setShape(shapeValue);
7907 result->setSizingBehavior(sizeValue);
7909 // Or, two lengths or percentages
7910 RefPtr<CSSPrimitiveValue> horizontalSize;
7911 RefPtr<CSSPrimitiveValue> verticalSize;
7913 if (!shapeValue && !sizeValue) {
7914 if (validUnit(a, FLength | FPercent)) {
7915 horizontalSize = createPrimitiveNumericValue(a);
7923 if (validUnit(a, FLength | FPercent)) {
7924 verticalSize = createPrimitiveNumericValue(a);
7933 // Must have neither or both.
7934 if (!horizontalSize != !verticalSize)
7937 result->setEndHorizontalSize(horizontalSize);
7938 result->setEndVerticalSize(verticalSize);
7940 if (!parseGradientColorStops(args, result.get(), expectComma))
7943 gradient = result.release();
7947 bool BisonCSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7949 RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient);
7951 CSSParserValueList* args = valueList->current()->function->args.get();
7952 if (!args || !args->size())
7955 CSSParserValue* a = args->current();
7959 bool expectComma = false;
7961 if (validUnit(a, FAngle, HTMLStandardMode)) {
7962 result->setAngle(createPrimitiveNumericValue(a));
7966 } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) {
7967 // to [ [left | right] || [top | bottom] ]
7972 RefPtr<CSSPrimitiveValue> endX, endY;
7973 RefPtr<CSSPrimitiveValue> location;
7974 bool isHorizontal = false;
7976 location = valueFromSideKeyword(a, isHorizontal);
7989 location = valueFromSideKeyword(a, isHorizontal);
8005 result->setFirstX(endX.release());
8006 result->setFirstY(endY.release());
8009 if (!parseGradientColorStops(args, result.get(), expectComma))
8012 if (!result->stopCount())
8015 gradient = result.release();
8019 bool BisonCSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
8021 RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
8023 CSSParserValueList* args = valueList->current()->function->args.get();
8024 if (!args || !args->size())
8027 CSSParserValue* a = args->current();
8031 bool expectComma = false;
8033 RefPtr<CSSPrimitiveValue> shapeValue;
8034 RefPtr<CSSPrimitiveValue> sizeValue;
8035 RefPtr<CSSPrimitiveValue> horizontalSize;
8036 RefPtr<CSSPrimitiveValue> verticalSize;
8038 // First part of grammar, the size/shape clause:
8039 // [ circle || <length> ] |
8040 // [ ellipse || [ <length> | <percentage> ]{2} ] |
8041 // [ [ circle | ellipse] || <size-keyword> ]
8042 for (int i = 0; i < 3; ++i) {
8043 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
8044 bool badIdent = false;
8046 case CSSValueCircle:
8047 case CSSValueEllipse:
8050 shapeValue = cssValuePool().createIdentifierValue(a->id);
8052 case CSSValueClosestSide:
8053 case CSSValueClosestCorner:
8054 case CSSValueFarthestSide:
8055 case CSSValueFarthestCorner:
8056 if (sizeValue || horizontalSize)
8058 sizeValue = cssValuePool().createIdentifierValue(a->id);
8070 } else if (validUnit(a, FLength | FPercent)) {
8072 if (sizeValue || horizontalSize)
8074 horizontalSize = createPrimitiveNumericValue(a);
8080 if (validUnit(a, FLength | FPercent)) {
8081 verticalSize = createPrimitiveNumericValue(a);
8091 // You can specify size as a keyword or a length/percentage, not both.
8092 if (sizeValue && horizontalSize)
8094 // Circles must have 0 or 1 lengths.
8095 if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize)
8097 // Ellipses must have 0 or 2 length/percentages.
8098 if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
8100 // If there's only one size, it must be a length.
8101 if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
8104 result->setShape(shapeValue);
8105 result->setSizingBehavior(sizeValue);
8106 result->setEndHorizontalSize(horizontalSize);
8107 result->setEndVerticalSize(verticalSize);
8109 // Second part of grammar, the center-position clause:
8111 RefPtr<CSSValue> centerX;
8112 RefPtr<CSSValue> centerY;
8113 if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) {
8118 parseFillPosition(args, centerX, centerY);
8119 if (!(centerX && centerY))
8122 a = args->current();
8125 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
8126 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
8127 // Right now, CSS radial gradients have the same start and end centers.
8128 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
8129 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
8132 if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
8135 if (!parseGradientColorStops(args, result.get(), expectComma))
8138 gradient = result.release();
8142 bool BisonCSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
8144 CSSParserValue* a = valueList->current();
8146 // Now look for color stops.
8148 // Look for the comma before the next stop.
8153 a = valueList->next();
8158 // <color-stop> = <color> [ <percentage> | <length> ]?
8159 CSSGradientColorStop stop;
8160 stop.m_color = parseGradientColorOrKeyword(this, a);
8164 a = valueList->next();
8166 if (validUnit(a, FLength | FPercent)) {
8167 stop.m_position = createPrimitiveNumericValue(a);
8168 a = valueList->next();
8172 gradient->addStop(stop);
8176 // Must have 2 or more stops to be valid.
8177 return gradient->stopCount() >= 2;
8180 bool BisonCSSParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
8182 CSSParserValue* val = valueList->current();
8184 if (val->unit != CSSParserValue::Function)
8187 if (equalIgnoringCase(val->function->name, "-webkit-gradient("))
8188 return parseDeprecatedGradient(valueList, value);
8190 if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient("))
8191 return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
8193 if (equalIgnoringCase(val->function->name, "linear-gradient("))
8194 return parseLinearGradient(valueList, value, NonRepeating);
8196 if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient("))
8197 return parseDeprecatedLinearGradient(valueList, value, Repeating);
8199 if (equalIgnoringCase(val->function->name, "repeating-linear-gradient("))
8200 return parseLinearGradient(valueList, value, Repeating);
8202 if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient("))
8203 return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
8205 if (equalIgnoringCase(val->function->name, "radial-gradient("))
8206 return parseRadialGradient(valueList, value, NonRepeating);
8208 if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient("))
8209 return parseDeprecatedRadialGradient(valueList, value, Repeating);
8211 if (equalIgnoringCase(val->function->name, "repeating-radial-gradient("))
8212 return parseRadialGradient(valueList, value, Repeating);
8214 if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
8215 return parseCanvas(valueList, value);
8217 if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
8218 return parseCrossfade(valueList, value);
8223 bool BisonCSSParser::parseCrossfade(CSSParserValueList* valueList, RefPtr<CSSValue>& crossfade)
8225 RefPtr<CSSCrossfadeValue> result;
8227 // Walk the arguments.
8228 CSSParserValueList* args = valueList->current()->function->args.get();
8229 if (!args || args->size() != 5)
8231 CSSParserValue* a = args->current();
8232 RefPtr<CSSValue> fromImageValue;
8233 RefPtr<CSSValue> toImageValue;
8235 // The first argument is the "from" image. It is a fill image.
8236 if (!a || !parseFillImage(args, fromImageValue))
8245 // The second argument is the "to" image. It is a fill image.
8246 if (!a || !parseFillImage(args, toImageValue))
8255 // The third argument is the crossfade value. It is a percentage or a fractional number.
8256 RefPtr<CSSPrimitiveValue> percentage;
8260 if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
8261 percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
8262 else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
8263 percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
8267 result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
8268 result->setPercentage(percentage);
8275 bool BisonCSSParser::parseCanvas(CSSParserValueList* valueList, RefPtr<CSSValue>& canvas)
8277 // Walk the arguments.
8278 CSSParserValueList* args = valueList->current()->function->args.get();
8279 if (!args || args->size() != 1)
8282 // The first argument is the canvas name. It is an identifier.
8283 CSSParserValue* value = args->current();
8284 if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
8287 canvas = CSSCanvasValue::create(value->string);
8291 PassRefPtr<CSSValue> BisonCSSParser::parseImageSet(CSSParserValueList* valueList)
8293 CSSParserValue* function = valueList->current();
8295 if (function->unit != CSSParserValue::Function)
8298 CSSParserValueList* functionArgs = valueList->current()->function->args.get();
8299 if (!functionArgs || !functionArgs->size() || !functionArgs->current())
8302 RefPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
8304 CSSParserValue* arg = functionArgs->current();
8306 if (arg->unit != CSSPrimitiveValue::CSS_URI)
8309 RefPtr<CSSImageValue> image = CSSImageValue::create(completeURL(arg->string));
8310 imageSet->append(image);
8312 arg = functionArgs->next();
8313 if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
8316 double imageScaleFactor = 0;
8317 const String& string = arg->string;
8318 unsigned length = string.length();
8321 if (string.is8Bit()) {
8322 const LChar* start = string.characters8();
8323 parseDouble(start, start + length, 'x', imageScaleFactor);
8325 const UChar* start = string.characters16();
8326 parseDouble(start, start + length, 'x', imageScaleFactor);
8328 if (imageScaleFactor <= 0)
8330 imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER));
8332 // If there are no more arguments, we're done.
8333 arg = functionArgs->next();
8337 // If there are more arguments, they should be after a comma.
8341 // Skip the comma and move on to the next argument.
8342 arg = functionArgs->next();
8345 return imageSet.release();
8348 class TransformOperationInfo {
8350 TransformOperationInfo(const CSSParserString& name)
8351 : m_type(CSSTransformValue::UnknownTransformOperation)
8353 , m_allowSingleArgument(false)
8354 , m_unit(BisonCSSParser::FUnknown)
8356 const UChar* characters;
8357 unsigned nameLength = name.length();
8359 const unsigned longestNameLength = 12;
8360 UChar characterBuffer[longestNameLength];
8361 if (name.is8Bit()) {
8362 unsigned length = std::min(longestNameLength, nameLength);
8363 const LChar* characters8 = name.characters8();
8364 for (unsigned i = 0; i < length; ++i)
8365 characterBuffer[i] = characters8[i];
8366 characters = characterBuffer;
8368 characters = name.characters16();
8370 SWITCH(characters, nameLength) {
8372 m_unit = BisonCSSParser::FAngle;
8373 m_type = CSSTransformValue::SkewTransformOperation;
8374 m_allowSingleArgument = true;
8378 m_unit = BisonCSSParser::FNumber;
8379 m_type = CSSTransformValue::ScaleTransformOperation;
8380 m_allowSingleArgument = true;
8384 m_unit = BisonCSSParser::FAngle;
8385 m_type = CSSTransformValue::SkewXTransformOperation;
8388 m_unit = BisonCSSParser::FAngle;
8389 m_type = CSSTransformValue::SkewYTransformOperation;
8392 m_unit = BisonCSSParser::FNumber;
8393 m_type = CSSTransformValue::MatrixTransformOperation;
8397 m_unit = BisonCSSParser::FAngle;
8398 m_type = CSSTransformValue::RotateTransformOperation;
8401 m_unit = BisonCSSParser::FNumber;
8402 m_type = CSSTransformValue::ScaleXTransformOperation;
8405 m_unit = BisonCSSParser::FNumber;
8406 m_type = CSSTransformValue::ScaleYTransformOperation;
8409 m_unit = BisonCSSParser::FNumber;
8410 m_type = CSSTransformValue::ScaleZTransformOperation;
8413 m_unit = BisonCSSParser::FNumber;
8414 m_type = CSSTransformValue::Scale3DTransformOperation;
8418 m_unit = BisonCSSParser::FAngle;
8419 m_type = CSSTransformValue::RotateXTransformOperation;
8422 m_unit = BisonCSSParser::FAngle;
8423 m_type = CSSTransformValue::RotateYTransformOperation;
8426 m_unit = BisonCSSParser::FAngle;
8427 m_type = CSSTransformValue::RotateZTransformOperation;
8430 m_unit = BisonCSSParser::FNumber;
8431 m_type = CSSTransformValue::Matrix3DTransformOperation;
8435 m_unit = BisonCSSParser::FNumber;
8436 m_type = CSSTransformValue::Rotate3DTransformOperation;
8439 CASE("translate(") {
8440 m_unit = BisonCSSParser::FLength | BisonCSSParser::FPercent;
8441 m_type = CSSTransformValue::TranslateTransformOperation;
8442 m_allowSingleArgument = true;
8445 CASE("translatex(") {
8446 m_unit = BisonCSSParser::FLength | BisonCSSParser::FPercent;
8447 m_type = CSSTransformValue::TranslateXTransformOperation;
8449 CASE("translatey(") {
8450 m_unit = BisonCSSParser::FLength | BisonCSSParser::FPercent;
8451 m_type = CSSTransformValue::TranslateYTransformOperation;
8453 CASE("translatez(") {
8454 m_unit = BisonCSSParser::FLength | BisonCSSParser::FPercent;
8455 m_type = CSSTransformValue::TranslateZTransformOperation;
8457 CASE("perspective(") {
8458 m_unit = BisonCSSParser::FNumber;
8459 m_type = CSSTransformValue::PerspectiveTransformOperation;
8461 CASE("translate3d(") {
8462 m_unit = BisonCSSParser::FLength | BisonCSSParser::FPercent;
8463 m_type = CSSTransformValue::Translate3DTransformOperation;
8469 CSSTransformValue::TransformOperationType type() const { return m_type; }
8470 unsigned argCount() const { return m_argCount; }
8471 BisonCSSParser::Units unit() const { return m_unit; }
8473 bool unknown() const { return m_type == CSSTransformValue::UnknownTransformOperation; }
8474 bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
8477 CSSTransformValue::TransformOperationType m_type;
8478 unsigned m_argCount;
8479 bool m_allowSingleArgument;
8480 BisonCSSParser::Units m_unit;
8483 PassRefPtr<CSSValueList> BisonCSSParser::parseTransform()
8488 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8489 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
8490 RefPtr<CSSValue> parsedTransformValue = parseTransformValue(value);
8491 if (!parsedTransformValue)
8494 list->append(parsedTransformValue.release());
8497 return list.release();
8500 PassRefPtr<CSSValue> BisonCSSParser::parseTransformValue(CSSParserValue *value)
8502 if (value->unit != CSSParserValue::Function || !value->function)
8505 // Every primitive requires at least one argument.
8506 CSSParserValueList* args = value->function->args.get();
8510 // See if the specified primitive is one we understand.
8511 TransformOperationInfo info(value->function->name);
8515 if (!info.hasCorrectArgCount(args->size()))
8518 // The transform is a list of functional primitives that specify transform operations.
8519 // We collect a list of CSSTransformValues, where each value specifies a single operation.
8521 // Create the new CSSTransformValue for this operation and add it to our list.
8522 RefPtr<CSSTransformValue> transformValue = CSSTransformValue::create(info.type());
8525 CSSParserValue* a = args->current();
8526 unsigned argNumber = 0;
8528 BisonCSSParser::Units unit = info.unit();
8530 if (info.type() == CSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
8531 // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
8532 if (!validUnit(a, FAngle, HTMLStandardMode))
8534 } else if (info.type() == CSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
8535 // 3rd param of translate3d() cannot be a percentage
8536 if (!validUnit(a, FLength, HTMLStandardMode))
8538 } else if (info.type() == CSSTransformValue::TranslateZTransformOperation && !argNumber) {
8539 // 1st param of translateZ() cannot be a percentage
8540 if (!validUnit(a, FLength, HTMLStandardMode))
8542 } else if (info.type() == CSSTransformValue::PerspectiveTransformOperation && !argNumber) {
8543 // 1st param of perspective() must be a non-negative number (deprecated) or length.
8544 if (!validUnit(a, FNumber | FLength | FNonNeg, HTMLStandardMode))
8546 } else if (!validUnit(a, unit, HTMLStandardMode))
8549 // Add the value to the current transform operation.
8550 transformValue->append(createPrimitiveNumericValue(a));
8555 if (a->unit != CSSParserValue::Operator || a->iValue != ',')
8562 return transformValue.release();
8565 bool BisonCSSParser::isBlendMode(CSSValueID valueID)
8567 return (valueID >= CSSValueMultiply && valueID <= CSSValueLuminosity)
8568 || valueID == CSSValueNormal
8569 || valueID == CSSValueOverlay;
8572 bool BisonCSSParser::isCompositeOperator(CSSValueID valueID)
8574 // FIXME: Add CSSValueDestination and CSSValueLighter when the Compositing spec updates.
8575 return valueID >= CSSValueClear && valueID <= CSSValueXor;
8578 static void filterInfoForName(const CSSParserString& name, CSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
8580 if (equalIgnoringCase(name, "grayscale("))
8581 filterType = CSSFilterValue::GrayscaleFilterOperation;
8582 else if (equalIgnoringCase(name, "sepia("))
8583 filterType = CSSFilterValue::SepiaFilterOperation;
8584 else if (equalIgnoringCase(name, "saturate("))
8585 filterType = CSSFilterValue::SaturateFilterOperation;
8586 else if (equalIgnoringCase(name, "hue-rotate("))
8587 filterType = CSSFilterValue::HueRotateFilterOperation;
8588 else if (equalIgnoringCase(name, "invert("))
8589 filterType = CSSFilterValue::InvertFilterOperation;
8590 else if (equalIgnoringCase(name, "opacity("))
8591 filterType = CSSFilterValue::OpacityFilterOperation;
8592 else if (equalIgnoringCase(name, "brightness("))
8593 filterType = CSSFilterValue::BrightnessFilterOperation;
8594 else if (equalIgnoringCase(name, "contrast("))
8595 filterType = CSSFilterValue::ContrastFilterOperation;
8596 else if (equalIgnoringCase(name, "blur("))
8597 filterType = CSSFilterValue::BlurFilterOperation;
8598 else if (equalIgnoringCase(name, "drop-shadow(")) {
8599 filterType = CSSFilterValue::DropShadowFilterOperation;
8600 maximumArgumentCount = 4; // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
8604 PassRefPtr<CSSFilterValue> BisonCSSParser::parseBuiltinFilterArguments(CSSParserValueList* args, CSSFilterValue::FilterOperationType filterType)
8606 RefPtr<CSSFilterValue> filterValue = CSSFilterValue::create(filterType);
8609 switch (filterType) {
8610 case CSSFilterValue::GrayscaleFilterOperation:
8611 case CSSFilterValue::SepiaFilterOperation:
8612 case CSSFilterValue::SaturateFilterOperation:
8613 case CSSFilterValue::InvertFilterOperation:
8614 case CSSFilterValue::OpacityFilterOperation:
8615 case CSSFilterValue::ContrastFilterOperation: {
8616 // One optional argument, 0-1 or 0%-100%, if missing use 100%.
8617 if (args->size() > 1)
8621 CSSParserValue* value = args->current();
8622 if (!validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode))
8625 double amount = value->fValue;
8627 // Saturate and Contrast allow values over 100%.
8628 if (filterType != CSSFilterValue::SaturateFilterOperation
8629 && filterType != CSSFilterValue::ContrastFilterOperation) {
8630 double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
8631 if (amount > maxAllowed)
8635 filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
8639 case CSSFilterValue::BrightnessFilterOperation: {
8640 // One optional argument, if missing use 100%.
8641 if (args->size() > 1)
8645 CSSParserValue* value = args->current();
8646 if (!validUnit(value, FNumber | FPercent, HTMLStandardMode))
8649 filterValue->append(cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
8653 case CSSFilterValue::HueRotateFilterOperation: {
8654 // hue-rotate() takes one optional angle.
8655 if (args->size() > 1)
8659 CSSParserValue* argument = args->current();
8660 if (!validUnit(argument, FAngle, HTMLStandardMode))
8663 filterValue->append(createPrimitiveNumericValue(argument));
8667 case CSSFilterValue::BlurFilterOperation: {
8668 // Blur takes a single length. Zero parameters are allowed.
8669 if (args->size() > 1)
8673 CSSParserValue* argument = args->current();
8674 if (!validUnit(argument, FLength | FNonNeg, HTMLStandardMode))
8677 filterValue->append(createPrimitiveNumericValue(argument));
8681 case CSSFilterValue::DropShadowFilterOperation: {
8682 // drop-shadow() takes a single shadow.
8683 RefPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter);
8684 if (!shadowValueList || shadowValueList->length() != 1)
8687 filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0));
8691 ASSERT_NOT_REACHED();
8693 return filterValue.release();
8696 PassRefPtr<CSSValueList> BisonCSSParser::parseFilter()
8701 // The filter is a list of functional primitives that specify individual operations.
8702 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8703 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
8704 if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function))
8707 CSSFilterValue::FilterOperationType filterType = CSSFilterValue::UnknownFilterOperation;
8709 // See if the specified primitive is one we understand.
8710 if (value->unit == CSSPrimitiveValue::CSS_URI) {
8711 RefPtr<CSSFilterValue> referenceFilterValue = CSSFilterValue::create(CSSFilterValue::ReferenceFilterOperation);
8712 list->append(referenceFilterValue);
8713 referenceFilterValue->append(CSSSVGDocumentValue::create(value->string));
8715 const CSSParserString name = value->function->name;
8716 unsigned maximumArgumentCount = 1;
8718 filterInfoForName(name, filterType, maximumArgumentCount);
8720 if (filterType == CSSFilterValue::UnknownFilterOperation)
8723 CSSParserValueList* args = value->function->args.get();
8727 RefPtr<CSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType);
8731 list->append(filterValue);
8735 return list.release();
8738 static bool validFlowName(const String& flowName)
8740 return !(equalIgnoringCase(flowName, "auto")
8741 || equalIgnoringCase(flowName, "default")
8742 || equalIgnoringCase(flowName, "inherit")
8743 || equalIgnoringCase(flowName, "initial")
8744 || equalIgnoringCase(flowName, "none"));
8748 bool BisonCSSParser::parseFlowThread(CSSPropertyID propId, bool important)
8750 ASSERT(propId == CSSPropertyWebkitFlowInto);
8751 ASSERT(RuntimeEnabledFeatures::cssRegionsEnabled());
8753 if (m_valueList->size() != 1)
8756 CSSParserValue* value = m_valueList->current();
8760 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
8763 if (value->id == CSSValueNone) {
8764 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
8768 String inputProperty = String(value->string);
8769 if (!inputProperty.isEmpty()) {
8770 if (!validFlowName(inputProperty))
8772 addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
8774 addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
8779 // -webkit-flow-from: none | <ident>
8780 bool BisonCSSParser::parseRegionThread(CSSPropertyID propId, bool important)
8782 ASSERT(propId == CSSPropertyWebkitFlowFrom);
8783 ASSERT(RuntimeEnabledFeatures::cssRegionsEnabled());
8785 if (m_valueList->size() != 1)
8788 CSSParserValue* value = m_valueList->current();
8792 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
8795 if (value->id == CSSValueNone)
8796 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
8798 String inputProperty = String(value->string);
8799 if (!inputProperty.isEmpty()) {
8800 if (!validFlowName(inputProperty))
8802 addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
8804 addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
8810 bool BisonCSSParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
8815 if (propId == CSSPropertyWebkitTransformOrigin) {
8816 propId1 = CSSPropertyWebkitTransformOriginX;
8817 propId2 = CSSPropertyWebkitTransformOriginY;
8818 propId3 = CSSPropertyWebkitTransformOriginZ;
8822 case CSSPropertyWebkitTransformOrigin:
8823 if (!parseTransformOriginShorthand(value, value2, value3))
8825 // parseTransformOriginShorthand advances the m_valueList pointer
8827 case CSSPropertyWebkitTransformOriginX: {
8828 value = parseFillPositionX(m_valueList.get());
8830 m_valueList->next();
8833 case CSSPropertyWebkitTransformOriginY: {
8834 value = parseFillPositionY(m_valueList.get());
8836 m_valueList->next();
8839 case CSSPropertyWebkitTransformOriginZ: {
8840 if (validUnit(m_valueList->current(), FLength))
8841 value = createPrimitiveNumericValue(m_valueList->current());
8843 m_valueList->next();
8847 ASSERT_NOT_REACHED();
8854 bool BisonCSSParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2)
8858 if (propId == CSSPropertyWebkitPerspectiveOrigin) {
8859 propId1 = CSSPropertyWebkitPerspectiveOriginX;
8860 propId2 = CSSPropertyWebkitPerspectiveOriginY;
8864 case CSSPropertyWebkitPerspectiveOrigin:
8865 if (m_valueList->size() > 2)
8867 parse2ValuesFillPosition(m_valueList.get(), value, value2);
8869 case CSSPropertyWebkitPerspectiveOriginX: {
8870 value = parseFillPositionX(m_valueList.get());
8872 m_valueList->next();
8875 case CSSPropertyWebkitPerspectiveOriginY: {
8876 value = parseFillPositionY(m_valueList.get());
8878 m_valueList->next();
8882 ASSERT_NOT_REACHED();
8889 bool BisonCSSParser::parseTouchAction(bool important)
8891 if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
8894 CSSParserValue* value = m_valueList->current();
8895 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8896 if (m_valueList->size() == 1 && value && (value->id == CSSValueAuto || value->id == CSSValueNone)) {
8897 list->append(cssValuePool().createIdentifierValue(value->id));
8898 addProperty(CSSPropertyTouchAction, list.release(), important);
8899 m_valueList->next();
8903 bool isValid = true;
8904 while (isValid && value) {
8905 switch (value->id) {
8907 case CSSValuePanY: {
8908 RefPtr<CSSValue> panValue = cssValuePool().createIdentifierValue(value->id);
8909 if (list->hasValue(panValue.get())) {
8913 list->append(panValue.release());
8921 value = m_valueList->next();
8924 if (list->length() && isValid) {
8925 addProperty(CSSPropertyTouchAction, list.release(), important);
8932 void BisonCSSParser::addTextDecorationProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important)
8934 // The text-decoration-line property takes priority over text-decoration, unless the latter has important priority set.
8935 if (propId == CSSPropertyTextDecoration && !important && !inShorthand()) {
8936 for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
8937 if (m_parsedProperties[i].id() == CSSPropertyTextDecorationLine)
8941 addProperty(propId, value, important);
8944 bool BisonCSSParser::parseTextDecoration(CSSPropertyID propId, bool important)
8946 if (propId == CSSPropertyTextDecorationLine
8947 && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
8950 CSSParserValue* value = m_valueList->current();
8951 if (value && value->id == CSSValueNone) {
8952 addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
8953 m_valueList->next();
8957 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8958 bool isValid = true;
8959 while (isValid && value) {
8960 switch (value->id) {
8961 case CSSValueUnderline:
8962 case CSSValueOverline:
8963 case CSSValueLineThrough:
8965 list->append(cssValuePool().createIdentifierValue(value->id));
8972 value = m_valueList->next();
8975 // Values are either valid or in shorthand scope.
8976 if (list->length() && (isValid || inShorthand())) {
8977 addTextDecorationProperty(propId, list.release(), important);
8984 bool BisonCSSParser::parseTextUnderlinePosition(bool important)
8986 // The text-underline-position property has syntax "auto | [ under || [ left | right ] ]".
8987 // However, values 'left' and 'right' are not implemented yet, so we will parse syntax
8988 // "auto | under" for now.
8989 CSSParserValue* value = m_valueList->current();
8990 switch (value->id) {
8993 if (m_valueList->next())
8995 addProperty(CSSPropertyTextUnderlinePosition, cssValuePool().createIdentifierValue(value->id), important);
9002 bool BisonCSSParser::parseTextEmphasisStyle(bool important)
9004 unsigned valueListSize = m_valueList->size();
9006 RefPtr<CSSPrimitiveValue> fill;
9007 RefPtr<CSSPrimitiveValue> shape;
9009 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9010 if (value->unit == CSSPrimitiveValue::CSS_STRING) {
9011 if (fill || shape || (valueListSize != 1 && !inShorthand()))
9013 addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important);
9014 m_valueList->next();
9018 if (value->id == CSSValueNone) {
9019 if (fill || shape || (valueListSize != 1 && !inShorthand()))
9021 addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important);
9022 m_valueList->next();
9026 if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
9029 fill = cssValuePool().createIdentifierValue(value->id);
9030 } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
9033 shape = cssValuePool().createIdentifierValue(value->id);
9034 } else if (!inShorthand())
9040 if (fill && shape) {
9041 RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
9042 parsedValues->append(fill.release());
9043 parsedValues->append(shape.release());
9044 addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
9048 addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
9052 addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
9059 PassRefPtr<CSSValue> BisonCSSParser::parseTextIndent()
9061 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9063 // <length> | <percentage> | inherit
9064 if (m_valueList->size() == 1) {
9065 CSSParserValue* value = m_valueList->current();
9066 if (!value->id && validUnit(value, FLength | FPercent)) {
9067 list->append(createPrimitiveNumericValue(value));
9068 m_valueList->next();
9069 return list.release();
9073 if (!RuntimeEnabledFeatures::css3TextEnabled())
9076 // The case where text-indent has only <length>(or <percentage>) value
9077 // is handled above if statement even though css3TextEnabled() returns true.
9079 // [ [ <length> | <percentage> ] && each-line ] | inherit
9080 if (m_valueList->size() != 2)
9083 CSSParserValue* firstValue = m_valueList->current();
9084 CSSParserValue* secondValue = m_valueList->next();
9085 CSSParserValue* lengthOrPercentageValue = 0;
9087 // [ <length> | <percentage> ] each-line
9088 if (validUnit(firstValue, FLength | FPercent) && secondValue->id == CSSValueEachLine)
9089 lengthOrPercentageValue = firstValue;
9090 // each-line [ <length> | <percentage> ]
9091 else if (firstValue->id == CSSValueEachLine && validUnit(secondValue, FLength | FPercent))
9092 lengthOrPercentageValue = secondValue;
9094 if (lengthOrPercentageValue) {
9095 list->append(createPrimitiveNumericValue(lengthOrPercentageValue));
9096 list->append(cssValuePool().createIdentifierValue(CSSValueEachLine));
9097 m_valueList->next();
9098 return list.release();
9104 bool BisonCSSParser::parseLineBoxContain(bool important)
9106 LineBoxContain lineBoxContain = LineBoxContainNone;
9108 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9109 if (value->id == CSSValueBlock) {
9110 if (lineBoxContain & LineBoxContainBlock)
9112 lineBoxContain |= LineBoxContainBlock;
9113 } else if (value->id == CSSValueInline) {
9114 if (lineBoxContain & LineBoxContainInline)
9116 lineBoxContain |= LineBoxContainInline;
9117 } else if (value->id == CSSValueFont) {
9118 if (lineBoxContain & LineBoxContainFont)
9120 lineBoxContain |= LineBoxContainFont;
9121 } else if (value->id == CSSValueGlyphs) {
9122 if (lineBoxContain & LineBoxContainGlyphs)
9124 lineBoxContain |= LineBoxContainGlyphs;
9125 } else if (value->id == CSSValueReplaced) {
9126 if (lineBoxContain & LineBoxContainReplaced)
9128 lineBoxContain |= LineBoxContainReplaced;
9129 } else if (value->id == CSSValueInlineBox) {
9130 if (lineBoxContain & LineBoxContainInlineBox)
9132 lineBoxContain |= LineBoxContainInlineBox;
9137 if (!lineBoxContain)
9140 addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
9144 bool BisonCSSParser::parseFontFeatureTag(CSSValueList* settings)
9146 // Feature tag name consists of 4-letter characters.
9147 static const unsigned tagNameLength = 4;
9149 CSSParserValue* value = m_valueList->current();
9150 // Feature tag name comes first
9151 if (value->unit != CSSPrimitiveValue::CSS_STRING)
9153 if (value->string.length() != tagNameLength)
9155 for (unsigned i = 0; i < tagNameLength; ++i) {
9156 // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
9157 UChar character = value->string[i];
9158 if (character < 0x20 || character > 0x7E)
9162 AtomicString tag = value->string;
9164 // Feature tag values could follow: <integer> | on | off
9165 value = m_valueList->next();
9167 if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
9168 tagValue = clampToInteger(value->fValue);
9171 m_valueList->next();
9172 } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
9173 tagValue = value->id == CSSValueOn;
9174 m_valueList->next();
9177 settings->append(CSSFontFeatureValue::create(tag, tagValue));
9181 bool BisonCSSParser::parseFontFeatureSettings(bool important)
9183 if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) {
9184 RefPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal);
9185 m_valueList->next();
9186 addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
9190 RefPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
9191 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9192 if (!parseFontFeatureTag(settings.get()))
9195 // If the list isn't parsed fully, the current value should be comma.
9196 value = m_valueList->current();
9197 if (value && !isComma(value))
9200 if (settings->length()) {
9201 addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important);
9207 bool BisonCSSParser::parseFontVariantLigatures(bool important)
9209 RefPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
9210 bool sawCommonLigaturesValue = false;
9211 bool sawDiscretionaryLigaturesValue = false;
9212 bool sawHistoricalLigaturesValue = false;
9214 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9215 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
9218 switch (value->id) {
9219 case CSSValueNoCommonLigatures:
9220 case CSSValueCommonLigatures:
9221 if (sawCommonLigaturesValue)
9223 sawCommonLigaturesValue = true;
9224 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9226 case CSSValueNoDiscretionaryLigatures:
9227 case CSSValueDiscretionaryLigatures:
9228 if (sawDiscretionaryLigaturesValue)
9230 sawDiscretionaryLigaturesValue = true;
9231 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9233 case CSSValueNoHistoricalLigatures:
9234 case CSSValueHistoricalLigatures:
9235 if (sawHistoricalLigaturesValue)
9237 sawHistoricalLigaturesValue = true;
9238 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9245 if (!ligatureValues->length())
9248 addProperty(CSSPropertyWebkitFontVariantLigatures, ligatureValues.release(), important);
9252 bool BisonCSSParser::parseCalculation(CSSParserValue* value, ValueRange range)
9254 ASSERT(isCalculation(value));
9256 CSSParserValueList* args = value->function->args.get();
9257 if (!args || !args->size())
9260 ASSERT(!m_parsedCalculation);
9261 m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
9263 if (!m_parsedCalculation)
9271 void BisonCSSParser::ensureLineEndings()
9274 m_lineEndings = lineEndings(*m_source);
9277 CSSParserSelector* BisonCSSParser::createFloatingSelectorWithTagName(const QualifiedName& tagQName)
9279 CSSParserSelector* selector = new CSSParserSelector(tagQName);
9280 m_floatingSelectors.append(selector);
9284 CSSParserSelector* BisonCSSParser::createFloatingSelector()
9286 CSSParserSelector* selector = new CSSParserSelector;
9287 m_floatingSelectors.append(selector);
9291 PassOwnPtr<CSSParserSelector> BisonCSSParser::sinkFloatingSelector(CSSParserSelector* selector)
9294 size_t index = m_floatingSelectors.reverseFind(selector);
9295 ASSERT(index != kNotFound);
9296 m_floatingSelectors.remove(index);
9298 return adoptPtr(selector);
9301 Vector<OwnPtr<CSSParserSelector> >* BisonCSSParser::createFloatingSelectorVector()
9303 Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >;
9304 m_floatingSelectorVectors.append(selectorVector);
9305 return selectorVector;
9308 PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > BisonCSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector)
9310 if (selectorVector) {
9311 size_t index = m_floatingSelectorVectors.reverseFind(selectorVector);
9312 ASSERT(index != kNotFound);
9313 m_floatingSelectorVectors.remove(index);
9315 return adoptPtr(selectorVector);
9318 CSSParserValueList* BisonCSSParser::createFloatingValueList()
9320 CSSParserValueList* list = new CSSParserValueList;
9321 m_floatingValueLists.append(list);
9325 PassOwnPtr<CSSParserValueList> BisonCSSParser::sinkFloatingValueList(CSSParserValueList* list)
9328 size_t index = m_floatingValueLists.reverseFind(list);
9329 ASSERT(index != kNotFound);
9330 m_floatingValueLists.remove(index);
9332 return adoptPtr(list);
9335 CSSParserFunction* BisonCSSParser::createFloatingFunction()
9337 CSSParserFunction* function = new CSSParserFunction;
9338 m_floatingFunctions.append(function);
9342 CSSParserFunction* BisonCSSParser::createFloatingFunction(const CSSParserString& name, PassOwnPtr<CSSParserValueList> args)
9344 CSSParserFunction* function = createFloatingFunction();
9345 function->name = name;
9346 function->args = args;
9350 PassOwnPtr<CSSParserFunction> BisonCSSParser::sinkFloatingFunction(CSSParserFunction* function)
9353 size_t index = m_floatingFunctions.reverseFind(function);
9354 ASSERT(index != kNotFound);
9355 m_floatingFunctions.remove(index);
9357 return adoptPtr(function);
9360 CSSParserValue& BisonCSSParser::sinkFloatingValue(CSSParserValue& value)
9362 if (value.unit == CSSParserValue::Function) {
9363 size_t index = m_floatingFunctions.reverseFind(value.function);
9364 ASSERT(index != kNotFound);
9365 m_floatingFunctions.remove(index);
9370 MediaQueryExp* BisonCSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
9372 m_floatingMediaQueryExp = MediaQueryExp::create(mediaFeature, values);
9373 return m_floatingMediaQueryExp.get();
9376 PassOwnPtr<MediaQueryExp> BisonCSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression)
9378 ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp);
9379 return m_floatingMediaQueryExp.release();
9382 Vector<OwnPtr<MediaQueryExp> >* BisonCSSParser::createFloatingMediaQueryExpList()
9384 m_floatingMediaQueryExpList = adoptPtr(new Vector<OwnPtr<MediaQueryExp> >);
9385 return m_floatingMediaQueryExpList.get();
9388 PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > BisonCSSParser::sinkFloatingMediaQueryExpList(Vector<OwnPtr<MediaQueryExp> >* list)
9390 ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList);
9391 return m_floatingMediaQueryExpList.release();
9394 MediaQuery* BisonCSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const AtomicString& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
9396 m_floatingMediaQuery = adoptPtr(new MediaQuery(restrictor, mediaType, expressions));
9397 return m_floatingMediaQuery.get();
9400 MediaQuery* BisonCSSParser::createFloatingMediaQuery(PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
9402 return createFloatingMediaQuery(MediaQuery::None, AtomicString("all", AtomicString::ConstructFromLiteral), expressions);
9405 MediaQuery* BisonCSSParser::createFloatingNotAllQuery()
9407 return createFloatingMediaQuery(MediaQuery::Not, AtomicString("all", AtomicString::ConstructFromLiteral), sinkFloatingMediaQueryExpList(createFloatingMediaQueryExpList()));
9410 PassOwnPtr<MediaQuery> BisonCSSParser::sinkFloatingMediaQuery(MediaQuery* query)
9412 ASSERT_UNUSED(query, query == m_floatingMediaQuery);
9413 return m_floatingMediaQuery.release();
9416 Vector<RefPtr<StyleKeyframe> >* BisonCSSParser::createFloatingKeyframeVector()
9418 m_floatingKeyframeVector = adoptPtr(new Vector<RefPtr<StyleKeyframe> >());
9419 return m_floatingKeyframeVector.get();
9422 PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > BisonCSSParser::sinkFloatingKeyframeVector(Vector<RefPtr<StyleKeyframe> >* keyframeVector)
9424 ASSERT_UNUSED(keyframeVector, m_floatingKeyframeVector == keyframeVector);
9425 return m_floatingKeyframeVector.release();
9428 MediaQuerySet* BisonCSSParser::createMediaQuerySet()
9430 RefPtr<MediaQuerySet> queries = MediaQuerySet::create();
9431 MediaQuerySet* result = queries.get();
9432 m_parsedMediaQuerySets.append(queries.release());
9436 StyleRuleBase* BisonCSSParser::createImportRule(const CSSParserString& url, MediaQuerySet* media)
9438 if (!media || !m_allowImportRules)
9440 RefPtr<StyleRuleImport> rule = StyleRuleImport::create(url, media);
9441 StyleRuleImport* result = rule.get();
9442 m_parsedRules.append(rule.release());
9446 StyleRuleBase* BisonCSSParser::createMediaRule(MediaQuerySet* media, RuleList* rules)
9448 m_allowImportRules = m_allowNamespaceDeclarations = false;
9449 RefPtr<StyleRuleMedia> rule;
9451 rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), *rules);
9453 RuleList emptyRules;
9454 rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), emptyRules);
9456 StyleRuleMedia* result = rule.get();
9457 m_parsedRules.append(rule.release());
9461 StyleRuleBase* BisonCSSParser::createSupportsRule(bool conditionIsSupported, RuleList* rules)
9463 m_allowImportRules = m_allowNamespaceDeclarations = false;
9465 RefPtr<CSSRuleSourceData> data = popSupportsRuleData();
9466 RefPtr<StyleRuleSupports> rule;
9467 String conditionText;
9468 unsigned conditionOffset = data->ruleHeaderRange.start + 9;
9469 unsigned conditionLength = data->ruleHeaderRange.length() - 9;
9471 if (m_tokenizer.is8BitSource())
9472 conditionText = String(m_tokenizer.m_dataStart8.get() + conditionOffset, conditionLength).stripWhiteSpace();
9474 conditionText = String(m_tokenizer.m_dataStart16.get() + conditionOffset, conditionLength).stripWhiteSpace();
9477 rule = StyleRuleSupports::create(conditionText, conditionIsSupported, *rules);
9479 RuleList emptyRules;
9480 rule = StyleRuleSupports::create(conditionText, conditionIsSupported, emptyRules);
9483 StyleRuleSupports* result = rule.get();
9484 m_parsedRules.append(rule.release());
9489 void BisonCSSParser::markSupportsRuleHeaderStart()
9491 if (!m_supportsRuleDataStack)
9492 m_supportsRuleDataStack = adoptPtr(new RuleSourceDataList());
9494 RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(CSSRuleSourceData::SUPPORTS_RULE);
9495 data->ruleHeaderRange.start = m_tokenizer.tokenStartOffset();
9496 m_supportsRuleDataStack->append(data);
9499 void BisonCSSParser::markSupportsRuleHeaderEnd()
9501 ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
9503 if (m_tokenizer.is8BitSource())
9504 m_supportsRuleDataStack->last()->ruleHeaderRange.end = m_tokenizer.tokenStart<LChar>() - m_tokenizer.m_dataStart8.get();
9506 m_supportsRuleDataStack->last()->ruleHeaderRange.end = m_tokenizer.tokenStart<UChar>() - m_tokenizer.m_dataStart16.get();
9509 PassRefPtr<CSSRuleSourceData> BisonCSSParser::popSupportsRuleData()
9511 ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
9512 RefPtr<CSSRuleSourceData> data = m_supportsRuleDataStack->last();
9513 m_supportsRuleDataStack->removeLast();
9514 return data.release();
9517 BisonCSSParser::RuleList* BisonCSSParser::createRuleList()
9519 OwnPtr<RuleList> list = adoptPtr(new RuleList);
9520 RuleList* listPtr = list.get();
9522 m_parsedRuleLists.append(list.release());
9526 BisonCSSParser::RuleList* BisonCSSParser::appendRule(RuleList* ruleList, StyleRuleBase* rule)
9530 ruleList = createRuleList();
9531 ruleList->append(rule);
9536 template <typename CharacterType>
9537 ALWAYS_INLINE static void makeLower(const CharacterType* input, CharacterType* output, unsigned length)
9539 // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
9540 // that can potentially change the length of the string rather than the character
9541 // by character kind. If we don't need Unicode lowercasing, it would be good to
9542 // simplify this function.
9544 if (charactersAreAllASCII(input, length)) {
9545 // Fast case for all-ASCII.
9546 for (unsigned i = 0; i < length; i++)
9547 output[i] = toASCIILower(input[i]);
9549 for (unsigned i = 0; i < length; i++)
9550 output[i] = Unicode::toLower(input[i]);
9554 void BisonCSSParser::tokenToLowerCase(const CSSParserString& token)
9556 size_t length = token.length();
9557 if (m_tokenizer.is8BitSource()) {
9558 size_t offset = token.characters8() - m_tokenizer.m_dataStart8.get();
9559 makeLower(token.characters8(), m_tokenizer.m_dataStart8.get() + offset, length);
9561 size_t offset = token.characters16() - m_tokenizer.m_dataStart16.get();
9562 makeLower(token.characters16(), m_tokenizer.m_dataStart16.get() + offset, length);
9566 void BisonCSSParser::endInvalidRuleHeader()
9568 if (m_ruleHeaderType == CSSRuleSourceData::UNKNOWN_RULE)
9571 CSSParserLocation location;
9572 location.lineNumber = m_tokenizer.m_lineNumber;
9573 location.offset = m_ruleHeaderStartOffset;
9574 if (m_tokenizer.is8BitSource())
9575 location.token.init(m_tokenizer.m_dataStart8.get() + m_ruleHeaderStartOffset, 0);
9577 location.token.init(m_tokenizer.m_dataStart16.get() + m_ruleHeaderStartOffset, 0);
9579 reportError(location, m_ruleHeaderType == CSSRuleSourceData::STYLE_RULE ? InvalidSelectorCSSError : InvalidRuleCSSError);
9584 void BisonCSSParser::reportError(const CSSParserLocation&, CSSParserError)
9586 // FIXME: error reporting temporatily disabled.
9589 bool BisonCSSParser::isLoggingErrors()
9591 return m_logErrors && !m_ignoreErrors;
9594 void BisonCSSParser::logError(const String& message, const CSSParserLocation& location)
9596 unsigned lineNumberInStyleSheet;
9597 unsigned columnNumber = 0;
9598 if (InspectorInstrumentation::hasFrontends()) {
9599 ensureLineEndings();
9600 TextPosition tokenPosition = TextPosition::fromOffsetAndLineEndings(location.offset, *m_lineEndings);
9601 lineNumberInStyleSheet = tokenPosition.m_line.zeroBasedInt();
9602 columnNumber = (lineNumberInStyleSheet ? 0 : m_startPosition.m_column.zeroBasedInt()) + tokenPosition.m_column.zeroBasedInt();
9604 lineNumberInStyleSheet = location.lineNumber;
9606 PageConsole& console = m_styleSheet->singleOwnerDocument()->frameHost()->console();
9607 console.addMessage(CSSMessageSource, WarningMessageLevel, message, m_styleSheet->baseURL().string(), lineNumberInStyleSheet + m_startPosition.m_line.zeroBasedInt() + 1, columnNumber + 1);
9610 StyleRuleKeyframes* BisonCSSParser::createKeyframesRule(const String& name, PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > popKeyframes, bool isPrefixed)
9612 OwnPtr<Vector<RefPtr<StyleKeyframe> > > keyframes = popKeyframes;
9613 m_allowImportRules = m_allowNamespaceDeclarations = false;
9614 RefPtr<StyleRuleKeyframes> rule = StyleRuleKeyframes::create();
9615 for (size_t i = 0; i < keyframes->size(); ++i)
9616 rule->parserAppendKeyframe(keyframes->at(i));
9617 rule->setName(name);
9618 rule->setVendorPrefixed(isPrefixed);
9619 StyleRuleKeyframes* rulePtr = rule.get();
9620 m_parsedRules.append(rule.release());
9624 StyleRuleBase* BisonCSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors)
9626 StyleRule* result = 0;
9628 m_allowImportRules = m_allowNamespaceDeclarations = false;
9629 RefPtr<StyleRule> rule = StyleRule::create();
9630 rule->parserAdoptSelectorVector(*selectors);
9631 if (m_hasFontFaceOnlyValues)
9632 deleteFontFaceOnlyValues();
9633 rule->setProperties(createStylePropertySet());
9634 result = rule.get();
9635 m_parsedRules.append(rule.release());
9641 StyleRuleBase* BisonCSSParser::createFontFaceRule()
9643 m_allowImportRules = m_allowNamespaceDeclarations = false;
9644 for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
9645 CSSProperty& property = m_parsedProperties[i];
9646 if (property.id() == CSSPropertyFontVariant && property.value()->isPrimitiveValue())
9647 property.wrapValueInCommaSeparatedList();
9648 else if (property.id() == CSSPropertyFontFamily && (!property.value()->isValueList() || toCSSValueList(property.value())->length() != 1)) {
9649 // Unlike font-family property, font-family descriptor in @font-face rule
9650 // has to be a value list with exactly one family name. It cannot have a
9651 // have 'initial' value and cannot 'inherit' from parent.
9652 // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
9657 RefPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create();
9658 rule->setProperties(createStylePropertySet());
9660 StyleRuleFontFace* result = rule.get();
9661 m_parsedRules.append(rule.release());
9663 m_styleSheet->setHasFontFaceRule(true);
9667 void BisonCSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
9669 if (!m_styleSheet || !m_allowNamespaceDeclarations)
9671 m_allowImportRules = false;
9672 m_styleSheet->parserAddNamespace(prefix, uri);
9673 if (prefix.isEmpty() && !uri.isNull())
9674 m_defaultNamespace = uri;
9677 QualifiedName BisonCSSParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName)
9680 return QualifiedName(prefix, localName, m_defaultNamespace);
9681 return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix));
9684 CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector* specifiers)
9686 if (m_defaultNamespace != starAtom || specifiers->needsCrossingTreeScopeBoundary())
9687 return rewriteSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true);
9688 if (CSSParserSelector* distributedPseudoElementSelector = specifiers->findDistributedPseudoElementSelector()) {
9689 specifiers->prependTagSelector(QualifiedName(nullAtom, starAtom, m_defaultNamespace), /*tagIsForNamespaceRule*/true);
9690 return rewriteSpecifiersForShadowDistributed(specifiers, distributedPseudoElementSelector);
9695 CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
9697 AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
9698 QualifiedName tag(namespacePrefix, elementName, determinedNamespace);
9700 if (CSSParserSelector* distributedPseudoElementSelector = specifiers->findDistributedPseudoElementSelector()) {
9701 specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
9702 return rewriteSpecifiersForShadowDistributed(specifiers, distributedPseudoElementSelector);
9705 if (specifiers->needsCrossingTreeScopeBoundary())
9706 return rewriteSpecifiersWithElementNameForCustomPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
9708 if (specifiers->isContentPseudoElement())
9709 return rewriteSpecifiersWithElementNameForContentPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
9711 if (tag == anyQName())
9713 if (!(specifiers->pseudoType() == CSSSelector::PseudoCue))
9714 specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
9718 CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementNameForCustomPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
9720 if (m_useCounter && specifiers->pseudoType() == CSSSelector::PseudoUserAgentCustomElement)
9721 m_useCounter->count(UseCounter::CSSPseudoElementUserAgentCustomPseudo);
9723 CSSParserSelector* lastShadowPseudo = specifiers;
9724 CSSParserSelector* history = specifiers;
9725 while (history->tagHistory()) {
9726 history = history->tagHistory();
9727 if (history->needsCrossingTreeScopeBoundary() || history->hasShadowPseudo())
9728 lastShadowPseudo = history;
9731 if (lastShadowPseudo->tagHistory()) {
9732 if (tag != anyQName())
9733 lastShadowPseudo->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
9737 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
9738 // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
9739 OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
9740 lastShadowPseudo->setTagHistory(elementNameSelector.release());
9741 lastShadowPseudo->setRelation(CSSSelector::ShadowPseudo);
9745 CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementNameForContentPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
9747 CSSParserSelector* last = specifiers;
9748 CSSParserSelector* history = specifiers;
9749 while (history->tagHistory()) {
9750 history = history->tagHistory();
9751 if (history->isContentPseudoElement() || history->relationIsAffectedByPseudoContent())
9755 if (last->tagHistory()) {
9756 if (tag != anyQName())
9757 last->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
9761 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
9762 // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
9763 OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
9764 last->setTagHistory(elementNameSelector.release());
9765 last->setRelation(CSSSelector::SubSelector);
9769 CSSParserSelector* BisonCSSParser::rewriteSpecifiersForShadowDistributed(CSSParserSelector* specifiers, CSSParserSelector* distributedPseudoElementSelector)
9772 m_useCounter->count(UseCounter::CSSPseudoElementPrefixedDistributed);
9773 CSSParserSelector* argumentSelector = distributedPseudoElementSelector->functionArgumentSelector();
9774 ASSERT(argumentSelector);
9775 ASSERT(!specifiers->isDistributedPseudoElement());
9776 for (CSSParserSelector* end = specifiers; end->tagHistory(); end = end->tagHistory()) {
9777 if (end->tagHistory()->isDistributedPseudoElement()) {
9778 end->clearTagHistory();
9782 CSSParserSelector* end = argumentSelector;
9783 while (end->tagHistory())
9784 end = end->tagHistory();
9786 switch (end->relation()) {
9787 case CSSSelector::Child:
9788 case CSSSelector::Descendant:
9789 end->setTagHistory(sinkFloatingSelector(specifiers));
9790 end->setRelationIsAffectedByPseudoContent();
9791 return argumentSelector;
9797 CSSParserSelector* BisonCSSParser::rewriteSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier)
9799 if (newSpecifier->needsCrossingTreeScopeBoundary()) {
9800 // Unknown pseudo element always goes at the top of selector chain.
9801 newSpecifier->appendTagHistory(CSSSelector::ShadowPseudo, sinkFloatingSelector(specifiers));
9802 return newSpecifier;
9804 if (newSpecifier->isContentPseudoElement()) {
9805 newSpecifier->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(specifiers));
9806 return newSpecifier;
9808 if (specifiers->needsCrossingTreeScopeBoundary()) {
9809 // Specifiers for unknown pseudo element go right behind it in the chain.
9810 specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::ShadowPseudo);
9813 if (specifiers->isContentPseudoElement()) {
9814 specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::SubSelector);
9817 specifiers->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier));
9821 StyleRuleBase* BisonCSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector)
9823 // FIXME: Margin at-rules are ignored.
9824 m_allowImportRules = m_allowNamespaceDeclarations = false;
9825 StyleRulePage* pageRule = 0;
9827 RefPtr<StyleRulePage> rule = StyleRulePage::create();
9828 Vector<OwnPtr<CSSParserSelector> > selectorVector;
9829 selectorVector.append(pageSelector);
9830 rule->parserAdoptSelectorVector(selectorVector);
9831 rule->setProperties(createStylePropertySet());
9832 pageRule = rule.get();
9833 m_parsedRules.append(rule.release());
9839 void BisonCSSParser::setReusableRegionSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectors)
9842 m_reusableRegionSelectorVector.swap(*selectors);
9845 StyleRuleBase* BisonCSSParser::createRegionRule(Vector<OwnPtr<CSSParserSelector> >* regionSelector, RuleList* rules)
9848 m_useCounter->count(UseCounter::CSSWebkitRegionAtRule);
9850 if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !regionSelector || !rules)
9853 m_allowImportRules = m_allowNamespaceDeclarations = false;
9855 RefPtr<StyleRuleRegion> regionRule = StyleRuleRegion::create(regionSelector, *rules);
9857 StyleRuleRegion* result = regionRule.get();
9858 m_parsedRules.append(regionRule.release());
9860 m_observer->startEndUnknownRule();
9865 StyleRuleBase* BisonCSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
9867 // FIXME: Implement margin at-rule here, using:
9868 // - marginBox: margin box
9869 // - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_parsedProperties.size()] are for this at-rule.
9870 // Don't forget to also update the action for page symbol in CSSGrammar.y such that margin at-rule data is cleared if page_selector is invalid.
9872 endDeclarationsForMarginBox();
9873 return 0; // until this method is implemented.
9876 void BisonCSSParser::startDeclarationsForMarginBox()
9878 m_numParsedPropertiesBeforeMarginBox = m_parsedProperties.size();
9881 void BisonCSSParser::endDeclarationsForMarginBox()
9883 rollbackLastProperties(m_parsedProperties.size() - m_numParsedPropertiesBeforeMarginBox);
9884 m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
9887 void BisonCSSParser::deleteFontFaceOnlyValues()
9889 ASSERT(m_hasFontFaceOnlyValues);
9890 for (unsigned i = 0; i < m_parsedProperties.size();) {
9891 CSSProperty& property = m_parsedProperties[i];
9892 if (property.id() == CSSPropertyFontVariant && property.value()->isValueList()) {
9893 m_parsedProperties.remove(i);
9900 StyleKeyframe* BisonCSSParser::createKeyframe(CSSParserValueList* keys)
9902 OwnPtr<Vector<double> > keyVector = StyleKeyframe::createKeyList(keys);
9903 if (keyVector->isEmpty())
9906 RefPtr<StyleKeyframe> keyframe = StyleKeyframe::create();
9907 keyframe->setKeys(keyVector.release());
9908 keyframe->setProperties(createStylePropertySet());
9912 StyleKeyframe* keyframePtr = keyframe.get();
9913 m_parsedKeyframes.append(keyframe.release());
9917 void BisonCSSParser::invalidBlockHit()
9919 if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
9920 m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
9923 void BisonCSSParser::startRule()
9928 ASSERT(m_ruleHasHeader);
9929 m_ruleHasHeader = false;
9932 void BisonCSSParser::endRule(bool valid)
9937 if (m_ruleHasHeader)
9938 m_observer->endRuleBody(m_tokenizer.safeUserStringTokenOffset(), !valid);
9939 m_ruleHasHeader = true;
9942 void BisonCSSParser::startRuleHeader(CSSRuleSourceData::Type ruleType)
9944 resumeErrorLogging();
9945 m_ruleHeaderType = ruleType;
9946 m_ruleHeaderStartOffset = m_tokenizer.safeUserStringTokenOffset();
9947 m_ruleHeaderStartLineNumber = m_tokenizer.m_tokenStartLineNumber;
9949 ASSERT(!m_ruleHasHeader);
9950 m_observer->startRuleHeader(ruleType, m_ruleHeaderStartOffset);
9951 m_ruleHasHeader = true;
9955 void BisonCSSParser::endRuleHeader()
9957 ASSERT(m_ruleHeaderType != CSSRuleSourceData::UNKNOWN_RULE);
9958 m_ruleHeaderType = CSSRuleSourceData::UNKNOWN_RULE;
9960 ASSERT(m_ruleHasHeader);
9961 m_observer->endRuleHeader(m_tokenizer.safeUserStringTokenOffset());
9965 void BisonCSSParser::startSelector()
9968 m_observer->startSelector(m_tokenizer.safeUserStringTokenOffset());
9971 void BisonCSSParser::endSelector()
9974 m_observer->endSelector(m_tokenizer.safeUserStringTokenOffset());
9977 void BisonCSSParser::startRuleBody()
9980 m_observer->startRuleBody(m_tokenizer.safeUserStringTokenOffset());
9983 void BisonCSSParser::startProperty()
9985 resumeErrorLogging();
9987 m_observer->startProperty(m_tokenizer.safeUserStringTokenOffset());
9990 void BisonCSSParser::endProperty(bool isImportantFound, bool isPropertyParsed, CSSParserError errorType)
9992 m_id = CSSPropertyInvalid;
9994 m_observer->endProperty(isImportantFound, isPropertyParsed, m_tokenizer.safeUserStringTokenOffset(), errorType);
9997 void BisonCSSParser::startEndUnknownRule()
10000 m_observer->startEndUnknownRule();
10003 StyleRuleBase* BisonCSSParser::createViewportRule()
10005 // Allow @viewport rules from UA stylesheets even if the feature is disabled.
10006 if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode()))
10009 m_allowImportRules = m_allowNamespaceDeclarations = false;
10011 RefPtr<StyleRuleViewport> rule = StyleRuleViewport::create();
10013 rule->setProperties(createStylePropertySet());
10016 StyleRuleViewport* result = rule.get();
10017 m_parsedRules.append(rule.release());
10022 bool BisonCSSParser::parseViewportProperty(CSSPropertyID propId, bool important)
10024 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
10026 CSSParserValue* value = m_valueList->current();
10030 CSSValueID id = value->id;
10031 bool validPrimitive = false;
10034 case CSSPropertyMinWidth: // auto | extend-to-zoom | <length> | <percentage>
10035 case CSSPropertyMaxWidth:
10036 case CSSPropertyMinHeight:
10037 case CSSPropertyMaxHeight:
10038 if (id == CSSValueAuto || id == CSSValueInternalExtendToZoom)
10039 validPrimitive = true;
10041 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
10043 case CSSPropertyWidth: // shorthand
10044 return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMaxWidth, important);
10045 case CSSPropertyHeight:
10046 return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyMaxHeight, important);
10047 case CSSPropertyMinZoom: // auto | <number> | <percentage>
10048 case CSSPropertyMaxZoom:
10049 case CSSPropertyZoom:
10050 if (id == CSSValueAuto)
10051 validPrimitive = true;
10053 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg));
10055 case CSSPropertyUserZoom: // zoom | fixed
10056 if (id == CSSValueZoom || id == CSSValueFixed)
10057 validPrimitive = true;
10059 case CSSPropertyOrientation: // auto | portrait | landscape
10060 if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandscape)
10061 validPrimitive = true;
10066 RefPtr<CSSValue> parsedValue;
10067 if (validPrimitive) {
10068 parsedValue = parseValidPrimitive(id, value);
10069 m_valueList->next();
10073 if (!m_valueList->current() || inShorthand()) {
10074 addProperty(propId, parsedValue.release(), important);
10082 bool BisonCSSParser::parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first, CSSPropertyID second, bool important)
10084 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
10085 unsigned numValues = m_valueList->size();
10090 ShorthandScope scope(this, propId);
10092 if (!parseViewportProperty(first, important))
10095 // If just one value is supplied, the second value
10096 // is implicitly initialized with the first value.
10097 if (numValues == 1)
10098 m_valueList->previous();
10100 return parseViewportProperty(second, important);
10103 template <typename CharacterType>
10104 static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
10106 char buffer[maxCSSPropertyNameLength + 1]; // 1 for null character
10108 for (unsigned i = 0; i != length; ++i) {
10109 CharacterType c = propertyName[i];
10110 if (c == 0 || c >= 0x7F)
10111 return CSSPropertyInvalid; // illegal character
10112 buffer[i] = toASCIILower(c);
10114 buffer[length] = '\0';
10116 const char* name = buffer;
10117 const Property* hashTableEntry = findProperty(name, length);
10118 return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
10121 CSSPropertyID cssPropertyID(const String& string)
10123 unsigned length = string.length();
10126 return CSSPropertyInvalid;
10127 if (length > maxCSSPropertyNameLength)
10128 return CSSPropertyInvalid;
10130 return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
10133 CSSPropertyID cssPropertyID(const CSSParserString& string)
10135 unsigned length = string.length();
10138 return CSSPropertyInvalid;
10139 if (length > maxCSSPropertyNameLength)
10140 return CSSPropertyInvalid;
10142 return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
10145 template <typename CharacterType>
10146 static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
10148 char buffer[maxCSSValueKeywordLength + 1]; // 1 for null character
10150 for (unsigned i = 0; i != length; ++i) {
10151 CharacterType c = valueKeyword[i];
10152 if (c == 0 || c >= 0x7F)
10153 return CSSValueInvalid; // illegal character
10154 buffer[i] = WTF::toASCIILower(c);
10156 buffer[length] = '\0';
10158 const Value* hashTableEntry = findValue(buffer, length);
10159 return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSValueInvalid;
10162 CSSValueID cssValueKeywordID(const CSSParserString& string)
10164 unsigned length = string.length();
10166 return CSSValueInvalid;
10167 if (length > maxCSSValueKeywordLength)
10168 return CSSValueInvalid;
10170 return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
10173 bool isValidNthToken(const CSSParserString& token)
10175 // The tokenizer checks for the construct of an+b.
10176 // However, since the {ident} rule precedes the {nth} rule, some of those
10177 // tokens are identified as string literal. Furthermore we need to accept
10178 // "odd" and "even" which does not match to an+b.
10179 return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
10180 || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");