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/CSSGridTemplateAreasValue.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/Counter.h"
66 #include "core/css/HashTools.h"
67 #include "core/css/MediaList.h"
68 #include "core/css/MediaQueryExp.h"
69 #include "core/css/Pair.h"
70 #include "core/css/Rect.h"
71 #include "core/css/StylePropertySet.h"
72 #include "core/css/StyleRule.h"
73 #include "core/css/StyleRuleImport.h"
74 #include "core/css/StyleSheetContents.h"
75 #include "core/css/parser/CSSParserIdioms.h"
76 #include "core/dom/Document.h"
77 #include "core/frame/FrameHost.h"
78 #include "core/frame/PageConsole.h"
79 #include "core/frame/Settings.h"
80 #include "core/html/parser/HTMLParserIdioms.h"
81 #include "core/inspector/InspectorInstrumentation.h"
82 #include "core/rendering/RenderTheme.h"
83 #include "core/svg/SVGParserUtilities.h"
84 #include "platform/FloatConversion.h"
85 #include "wtf/BitArray.h"
86 #include "wtf/HexNumber.h"
87 #include "wtf/text/StringBuffer.h"
88 #include "wtf/text/StringBuilder.h"
89 #include "wtf/text/StringImpl.h"
90 #include "wtf/text/TextEncoding.h"
96 extern int cssyydebug;
99 int cssyyparse(WebCore::BisonCSSParser*);
106 static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
107 static const double MAX_SCALE = 1000000;
109 template <unsigned N>
110 static bool equal(const CSSParserString& a, const char (&b)[N])
112 unsigned length = N - 1; // Ignore the trailing null character
113 if (a.length() != length)
116 return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar*>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length);
119 template <unsigned N>
120 static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
122 unsigned length = N - 1; // Ignore the trailing null character
123 if (a.length() != length)
126 return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length);
129 template <unsigned N>
130 static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N])
132 ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrimitiveValue::CSS_STRING);
133 return equalIgnoringCase(value->string, b);
136 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> first, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> second, Pair::IdenticalValuesPolicy identicalValuesPolicy = Pair::DropIdenticalValues)
138 return cssValuePool().createValue(Pair::create(first, second, identicalValuesPolicy));
141 class AnimationParseContext {
143 AnimationParseContext()
144 : m_animationPropertyKeywordAllowed(true)
145 , m_firstAnimationCommitted(false)
146 , m_hasSeenAnimationPropertyKeyword(false)
150 void commitFirstAnimation()
152 m_firstAnimationCommitted = true;
155 bool hasCommittedFirstAnimation() const
157 return m_firstAnimationCommitted;
160 void commitAnimationPropertyKeyword()
162 m_animationPropertyKeywordAllowed = false;
165 bool animationPropertyKeywordAllowed() const
167 return m_animationPropertyKeywordAllowed;
170 bool hasSeenAnimationPropertyKeyword() const
172 return m_hasSeenAnimationPropertyKeyword;
175 void sawAnimationPropertyKeyword()
177 m_hasSeenAnimationPropertyKeyword = true;
181 bool m_animationPropertyKeywordAllowed;
182 bool m_firstAnimationCommitted;
183 bool m_hasSeenAnimationPropertyKeyword;
186 BisonCSSParser::BisonCSSParser(const CSSParserContext& context)
189 , m_id(CSSPropertyInvalid)
191 , m_supportsCondition(false)
192 , m_selectorListForParseSelector(0)
193 , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
194 , m_inParseShorthand(0)
195 , m_currentShorthand(CSSPropertyInvalid)
196 , m_implicitShorthand(false)
197 , m_hasFontFaceOnlyValues(false)
198 , m_hadSyntacticallyValidCSSRule(false)
200 , m_ignoreErrors(false)
201 , m_defaultNamespace(starAtom)
204 , m_ruleHeaderType(CSSRuleSourceData::UNKNOWN_RULE)
205 , m_allowImportRules(true)
206 , m_allowNamespaceDeclarations(true)
207 , m_inViewport(false)
213 CSSPropertySourceData::init();
216 BisonCSSParser::~BisonCSSParser()
220 deleteAllValues(m_floatingSelectors);
221 deleteAllValues(m_floatingSelectorVectors);
222 deleteAllValues(m_floatingValueLists);
223 deleteAllValues(m_floatingFunctions);
226 void BisonCSSParser::setupParser(const char* prefix, unsigned prefixLength, const String& string, const char* suffix, unsigned suffixLength)
228 m_tokenizer.setupTokenizer(prefix, prefixLength, string, suffix, suffixLength);
229 m_ruleHasHeader = true;
232 void BisonCSSParser::parseSheet(StyleSheetContents* sheet, const String& string, const TextPosition& startPosition, CSSParserObserver* observer, bool logErrors)
234 setStyleSheet(sheet);
235 m_defaultNamespace = starAtom; // Reset the default namespace.
236 TemporaryChange<CSSParserObserver*> scopedObsever(m_observer, observer);
237 m_logErrors = logErrors && sheet->singleOwnerDocument() && !sheet->baseURL().isEmpty() && sheet->singleOwnerDocument()->frameHost();
238 m_ignoreErrors = false;
239 m_tokenizer.m_lineNumber = 0;
240 m_startPosition = startPosition;
242 m_tokenizer.m_internal = false;
243 setupParser("", string, "");
245 sheet->shrinkToFit();
248 m_lineEndings.clear();
249 m_ignoreErrors = false;
251 m_tokenizer.m_internal = true;
254 PassRefPtr<StyleRuleBase> BisonCSSParser::parseRule(StyleSheetContents* sheet, const String& string)
256 setStyleSheet(sheet);
257 m_allowNamespaceDeclarations = false;
258 setupParser("@-internal-rule ", string, "");
260 return m_rule.release();
263 PassRefPtr<StyleKeyframe> BisonCSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string)
265 setStyleSheet(sheet);
266 setupParser("@-internal-keyframe-rule ", string, "");
268 return m_keyframe.release();
271 PassOwnPtr<Vector<double> > BisonCSSParser::parseKeyframeKeyList(const String& string)
273 setupParser("@-internal-keyframe-key-list ", string, "");
276 return StyleKeyframe::createKeyList(m_valueList.get());
279 bool BisonCSSParser::parseSupportsCondition(const String& string)
281 m_supportsCondition = false;
282 setupParser("@-internal-supports-condition ", string, "");
284 return m_supportsCondition;
287 static inline bool isColorPropertyID(CSSPropertyID propertyId)
289 switch (propertyId) {
290 case CSSPropertyColor:
291 case CSSPropertyBackgroundColor:
292 case CSSPropertyBorderBottomColor:
293 case CSSPropertyBorderLeftColor:
294 case CSSPropertyBorderRightColor:
295 case CSSPropertyBorderTopColor:
296 case CSSPropertyOutlineColor:
297 case CSSPropertyTextLineThroughColor:
298 case CSSPropertyTextOverlineColor:
299 case CSSPropertyTextUnderlineColor:
300 case CSSPropertyWebkitBorderAfterColor:
301 case CSSPropertyWebkitBorderBeforeColor:
302 case CSSPropertyWebkitBorderEndColor:
303 case CSSPropertyWebkitBorderStartColor:
304 case CSSPropertyWebkitColumnRuleColor:
305 case CSSPropertyWebkitTextEmphasisColor:
306 case CSSPropertyWebkitTextFillColor:
307 case CSSPropertyWebkitTextStrokeColor:
309 case CSSPropertyTextDecorationColor:
310 return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
316 static bool parseColorValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
318 ASSERT(!string.isEmpty());
319 bool quirksMode = isQuirksModeBehavior(cssParserMode);
320 if (!isColorPropertyID(propertyId))
322 CSSParserString cssString;
323 cssString.init(string);
324 CSSValueID valueID = cssValueKeywordID(cssString);
325 bool validPrimitive = false;
326 if (valueID == CSSValueWebkitText) {
327 validPrimitive = true;
328 } else if (valueID == CSSValueCurrentcolor) {
329 validPrimitive = true;
330 } else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
331 || (quirksMode && valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText)) {
332 validPrimitive = true;
335 if (validPrimitive) {
336 RefPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID);
337 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
341 if (!BisonCSSParser::fastParseColor(color, string, !quirksMode && string[0] != '#'))
343 RefPtr<CSSValue> value = cssValuePool().createColorValue(color);
344 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
348 static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
350 switch (propertyId) {
351 case CSSPropertyFontSize:
352 case CSSPropertyHeight:
353 case CSSPropertyWidth:
354 case CSSPropertyMinHeight:
355 case CSSPropertyMinWidth:
356 case CSSPropertyPaddingBottom:
357 case CSSPropertyPaddingLeft:
358 case CSSPropertyPaddingRight:
359 case CSSPropertyPaddingTop:
360 case CSSPropertyWebkitLogicalWidth:
361 case CSSPropertyWebkitLogicalHeight:
362 case CSSPropertyWebkitMinLogicalWidth:
363 case CSSPropertyWebkitMinLogicalHeight:
364 case CSSPropertyWebkitPaddingAfter:
365 case CSSPropertyWebkitPaddingBefore:
366 case CSSPropertyWebkitPaddingEnd:
367 case CSSPropertyWebkitPaddingStart:
368 acceptsNegativeNumbers = false;
370 case CSSPropertyShapeMargin:
371 case CSSPropertyShapePadding:
372 acceptsNegativeNumbers = false;
373 return RuntimeEnabledFeatures::cssShapesEnabled();
374 case CSSPropertyBottom:
375 case CSSPropertyLeft:
376 case CSSPropertyMarginBottom:
377 case CSSPropertyMarginLeft:
378 case CSSPropertyMarginRight:
379 case CSSPropertyMarginTop:
380 case CSSPropertyRight:
382 case CSSPropertyWebkitMarginAfter:
383 case CSSPropertyWebkitMarginBefore:
384 case CSSPropertyWebkitMarginEnd:
385 case CSSPropertyWebkitMarginStart:
386 acceptsNegativeNumbers = true;
393 template <typename CharacterType>
394 static inline bool parseSimpleLength(const CharacterType* characters, unsigned length, CSSPrimitiveValue::UnitTypes& unit, double& number)
396 if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
398 unit = CSSPrimitiveValue::CSS_PX;
399 } else if (length > 1 && characters[length - 1] == '%') {
401 unit = CSSPrimitiveValue::CSS_PERCENTAGE;
404 // We rely on charactersToDouble for validation as well. The function
405 // will set "ok" to "false" if the entire passed-in character range does
406 // not represent a double.
408 number = charactersToDouble(characters, length, &ok);
412 static bool parseSimpleLengthValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
414 ASSERT(!string.isEmpty());
415 bool acceptsNegativeNumbers;
417 // In @viewport, width and height are shorthands, not simple length values.
418 if (isCSSViewportParsingEnabledForMode(cssParserMode) || !isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
421 unsigned length = string.length();
423 CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
425 if (string.is8Bit()) {
426 if (!parseSimpleLength(string.characters8(), length, unit, number))
429 if (!parseSimpleLength(string.characters16(), length, unit, number))
433 if (unit == CSSPrimitiveValue::CSS_NUMBER) {
434 bool quirksMode = isQuirksModeBehavior(cssParserMode);
435 if (number && !quirksMode)
437 unit = CSSPrimitiveValue::CSS_PX;
439 if (number < 0 && !acceptsNegativeNumbers)
442 RefPtr<CSSValue> value = cssValuePool().createValue(number, unit);
443 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
447 static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext)
452 switch (propertyId) {
453 case CSSPropertyBorderCollapse: // collapse | separate | inherit
454 if (valueID == CSSValueCollapse || valueID == CSSValueSeparate)
457 case CSSPropertyBorderTopStyle: // <border-style> | inherit
458 case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
459 case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
460 case CSSPropertyBorderLeftStyle:
461 case CSSPropertyWebkitBorderAfterStyle:
462 case CSSPropertyWebkitBorderBeforeStyle:
463 case CSSPropertyWebkitBorderEndStyle:
464 case CSSPropertyWebkitBorderStartStyle:
465 case CSSPropertyWebkitColumnRuleStyle:
466 if (valueID >= CSSValueNone && valueID <= CSSValueDouble)
469 case CSSPropertyBoxSizing:
470 if (valueID == CSSValueBorderBox || valueID == CSSValueContentBox)
473 case CSSPropertyCaptionSide: // top | bottom | left | right | inherit
474 if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom)
477 case CSSPropertyClear: // none | left | right | both | inherit
478 if (valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth)
481 case CSSPropertyDirection: // ltr | rtl | inherit
482 if (valueID == CSSValueLtr || valueID == CSSValueRtl)
485 case CSSPropertyDisplay:
486 // inline | block | list-item | inline-block | table |
487 // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
488 // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none | inherit
489 // flex | inline-flex | -webkit-flex | -webkit-inline-flex | grid | inline-grid | lazy-block
490 if ((valueID >= CSSValueInline && valueID <= CSSValueInlineFlex) || valueID == CSSValueWebkitFlex || valueID == CSSValueWebkitInlineFlex || valueID == CSSValueNone)
492 if (valueID == CSSValueGrid || valueID == CSSValueInlineGrid)
493 return RuntimeEnabledFeatures::cssGridLayoutEnabled();
496 case CSSPropertyEmptyCells: // show | hide | inherit
497 if (valueID == CSSValueShow || valueID == CSSValueHide)
500 case CSSPropertyFloat: // left | right | none | center (for buggy CSS, maps to none)
501 if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone || valueID == CSSValueCenter)
504 case CSSPropertyFontStyle: // normal | italic | oblique | inherit
505 if (valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique)
508 case CSSPropertyImageRendering: // auto | optimizeContrast
509 if (valueID == CSSValueAuto || valueID == CSSValueWebkitOptimizeContrast)
512 case CSSPropertyIsolation: // auto | isolate
513 if (valueID == CSSValueAuto || valueID == CSSValueIsolate)
514 return RuntimeEnabledFeatures::cssCompositingEnabled();
516 case CSSPropertyListStylePosition: // inside | outside | inherit
517 if (valueID == CSSValueInside || valueID == CSSValueOutside)
520 case CSSPropertyListStyleType:
521 // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
522 // for the list of supported list-style-types.
523 if ((valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone)
526 case CSSPropertyObjectFit:
527 if (RuntimeEnabledFeatures::objectFitPositionEnabled()) {
528 if (valueID == CSSValueFill || valueID == CSSValueContain || valueID == CSSValueCover || valueID == CSSValueNone || valueID == CSSValueScaleDown)
532 case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit
533 if (valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble))
536 case CSSPropertyOverflowWrap: // normal | break-word
537 case CSSPropertyWordWrap:
538 if (valueID == CSSValueNormal || valueID == CSSValueBreakWord)
541 case CSSPropertyOverflowX: // visible | hidden | scroll | auto | overlay | inherit
542 if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay)
545 case CSSPropertyOverflowY: // visible | hidden | scroll | auto | overlay | inherit | -webkit-paged-x | -webkit-paged-y
546 if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY)
549 case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit
550 case CSSPropertyPageBreakBefore:
551 case CSSPropertyWebkitColumnBreakAfter:
552 case CSSPropertyWebkitColumnBreakBefore:
553 if (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight)
556 case CSSPropertyPageBreakInside: // avoid | auto | inherit
557 case CSSPropertyWebkitColumnBreakInside:
558 if (valueID == CSSValueAuto || valueID == CSSValueAvoid)
561 case CSSPropertyPointerEvents:
562 // none | visiblePainted | visibleFill | visibleStroke | visible |
563 // painted | fill | stroke | auto | all | bounding-box | inherit
564 if (valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueBoundingBox))
567 case CSSPropertyPosition: // static | relative | absolute | fixed | sticky | inherit
568 if (valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed
569 || (RuntimeEnabledFeatures::cssStickyPositionEnabled() && valueID == CSSValueSticky))
572 case CSSPropertyResize: // none | both | horizontal | vertical | auto
573 if (valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto)
576 case CSSPropertyScrollBehavior: // instant | smooth
577 if (valueID == CSSValueInstant || valueID == CSSValueSmooth)
578 return RuntimeEnabledFeatures::cssomSmoothScrollEnabled();
579 case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit
580 if (valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation)
583 case CSSPropertyTableLayout: // auto | fixed | inherit
584 if (valueID == CSSValueAuto || valueID == CSSValueFixed)
587 case CSSPropertyTextAlignLast:
588 // auto | start | end | left | right | center | justify
589 if (RuntimeEnabledFeatures::css3TextEnabled()
590 && ((valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto))
593 case CSSPropertyTextJustify:
594 // auto | none | inter-word | distribute
595 if (RuntimeEnabledFeatures::css3TextEnabled()
596 && (valueID == CSSValueInterWord || valueID == CSSValueDistribute || valueID == CSSValueAuto || valueID == CSSValueNone))
599 case CSSPropertyTextLineThroughMode:
600 case CSSPropertyTextOverlineMode:
601 case CSSPropertyTextUnderlineMode:
602 if (valueID == CSSValueContinuous || valueID == CSSValueSkipWhiteSpace)
605 case CSSPropertyTextLineThroughStyle:
606 case CSSPropertyTextOverlineStyle:
607 case CSSPropertyTextUnderlineStyle:
608 if (valueID == CSSValueNone || valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDashed || valueID == CSSValueDotDash || valueID == CSSValueDotDotDash || valueID == CSSValueWave)
611 case CSSPropertyTextOverflow: // clip | ellipsis
612 if (valueID == CSSValueClip || valueID == CSSValueEllipsis)
615 case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
616 if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision)
619 case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit
620 if ((valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone)
623 case CSSPropertyTouchActionDelay: // none | script
624 if (RuntimeEnabledFeatures::cssTouchActionDelayEnabled() && (valueID == CSSValueScript || valueID == CSSValueNone))
627 case CSSPropertyVisibility: // visible | hidden | collapse | inherit
628 if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse)
631 case CSSPropertyWebkitAppearance:
632 if ((valueID >= CSSValueCheckbox && valueID <= CSSValueTextarea) || valueID == CSSValueNone)
635 case CSSPropertyWebkitBackfaceVisibility:
636 if (valueID == CSSValueVisible || valueID == CSSValueHidden)
639 case CSSPropertyMixBlendMode:
640 if (RuntimeEnabledFeatures::cssCompositingEnabled() && (valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen
641 || valueID == CSSValueOverlay || valueID == CSSValueDarken || valueID == CSSValueLighten || valueID == CSSValueColorDodge
642 || valueID == CSSValueColorBurn || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference
643 || valueID == CSSValueExclusion || valueID == CSSValueHue || valueID == CSSValueSaturation || valueID == CSSValueColor
644 || valueID == CSSValueLuminosity))
647 case CSSPropertyWebkitBorderFit:
648 if (valueID == CSSValueBorder || valueID == CSSValueLines)
651 case CSSPropertyWebkitBoxAlign:
652 if (valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline)
655 case CSSPropertyWebkitBoxDecorationBreak:
656 if (valueID == CSSValueClone || valueID == CSSValueSlice)
659 case CSSPropertyWebkitBoxDirection:
660 if (valueID == CSSValueNormal || valueID == CSSValueReverse)
663 case CSSPropertyWebkitBoxLines:
664 if (valueID == CSSValueSingle || valueID == CSSValueMultiple)
667 case CSSPropertyWebkitBoxOrient:
668 if (valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis)
671 case CSSPropertyWebkitBoxPack:
672 if (valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify)
675 case CSSPropertyInternalCallback:
676 // This property is only injected programmatically, not parsed from stylesheets.
678 case CSSPropertyColumnFill:
679 if (RuntimeEnabledFeatures::regionBasedColumnsEnabled()) {
680 if (valueID == CSSValueAuto || valueID == CSSValueBalance)
684 case CSSPropertyAlignContent:
685 // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
686 if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch)
689 case CSSPropertyAlignItems:
690 // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
691 if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
694 case CSSPropertyAlignSelf:
695 // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
696 if (valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
699 case CSSPropertyFlexDirection:
700 if (valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse)
703 case CSSPropertyFlexWrap:
704 if (valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse)
707 case CSSPropertyJustifyContent:
708 // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
709 if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround)
712 case CSSPropertyFontKerning:
713 if (valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone)
716 case CSSPropertyWebkitFontSmoothing:
717 if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased)
720 case CSSPropertyGridAutoFlow:
721 if (valueID == CSSValueNone || valueID == CSSValueRow || valueID == CSSValueColumn)
722 return RuntimeEnabledFeatures::cssGridLayoutEnabled();
724 case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
725 if (valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace)
728 case CSSPropertyWebkitMarginAfterCollapse:
729 case CSSPropertyWebkitMarginBeforeCollapse:
730 case CSSPropertyWebkitMarginBottomCollapse:
731 case CSSPropertyWebkitMarginTopCollapse:
732 if (valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard)
735 case CSSPropertyInternalMarqueeDirection:
736 if (valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
737 || valueID == CSSValueUp || valueID == CSSValueAuto)
740 case CSSPropertyInternalMarqueeStyle:
741 if (valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate)
744 case CSSPropertyWebkitPrintColorAdjust:
745 if (valueID == CSSValueExact || valueID == CSSValueEconomy)
748 case CSSPropertyWebkitRtlOrdering:
749 if (valueID == CSSValueLogical || valueID == CSSValueVisual)
753 case CSSPropertyWebkitRubyPosition:
754 if (valueID == CSSValueBefore || valueID == CSSValueAfter)
758 case CSSPropertyWebkitTextCombine:
759 if (valueID == CSSValueNone || valueID == CSSValueHorizontal)
762 case CSSPropertyWebkitTextEmphasisPosition:
763 if (valueID == CSSValueOver || valueID == CSSValueUnder)
766 case CSSPropertyWebkitTextSecurity:
767 // disc | circle | square | none | inherit
768 if (valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone)
771 case CSSPropertyWebkitTransformStyle:
772 if (valueID == CSSValueFlat || valueID == CSSValuePreserve3d)
775 case CSSPropertyWebkitUserDrag: // auto | none | element
776 if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement)
779 case CSSPropertyWebkitUserModify: // read-only | read-write
780 if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly)
783 case CSSPropertyWebkitUserSelect: // auto | none | text | all
784 if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll)
787 case CSSPropertyWebkitWrapFlow:
788 if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
790 if (valueID == CSSValueAuto || valueID == CSSValueBoth || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueMaximum || valueID == CSSValueClear)
793 case CSSPropertyWebkitWrapThrough:
794 if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
796 if (valueID == CSSValueWrap || valueID == CSSValueNone)
799 case CSSPropertyWebkitWritingMode:
800 if (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
803 case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit
804 if (valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap)
807 case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
808 if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord)
812 ASSERT_NOT_REACHED();
818 static inline bool isKeywordPropertyID(CSSPropertyID propertyId)
820 switch (propertyId) {
821 case CSSPropertyMixBlendMode:
822 case CSSPropertyIsolation:
823 case CSSPropertyBorderBottomStyle:
824 case CSSPropertyBorderCollapse:
825 case CSSPropertyBorderLeftStyle:
826 case CSSPropertyBorderRightStyle:
827 case CSSPropertyBorderTopStyle:
828 case CSSPropertyBoxSizing:
829 case CSSPropertyCaptionSide:
830 case CSSPropertyClear:
831 case CSSPropertyDirection:
832 case CSSPropertyDisplay:
833 case CSSPropertyEmptyCells:
834 case CSSPropertyFloat:
835 case CSSPropertyFontStyle:
836 case CSSPropertyImageRendering:
837 case CSSPropertyListStylePosition:
838 case CSSPropertyListStyleType:
839 case CSSPropertyObjectFit:
840 case CSSPropertyOutlineStyle:
841 case CSSPropertyOverflowWrap:
842 case CSSPropertyOverflowX:
843 case CSSPropertyOverflowY:
844 case CSSPropertyPageBreakAfter:
845 case CSSPropertyPageBreakBefore:
846 case CSSPropertyPageBreakInside:
847 case CSSPropertyPointerEvents:
848 case CSSPropertyPosition:
849 case CSSPropertyResize:
850 case CSSPropertyScrollBehavior:
851 case CSSPropertySpeak:
852 case CSSPropertyTableLayout:
853 case CSSPropertyTextAlignLast:
854 case CSSPropertyTextJustify:
855 case CSSPropertyTextLineThroughMode:
856 case CSSPropertyTextLineThroughStyle:
857 case CSSPropertyTextOverflow:
858 case CSSPropertyTextOverlineMode:
859 case CSSPropertyTextOverlineStyle:
860 case CSSPropertyTextRendering:
861 case CSSPropertyTextTransform:
862 case CSSPropertyTextUnderlineMode:
863 case CSSPropertyTextUnderlineStyle:
864 case CSSPropertyTouchActionDelay:
865 case CSSPropertyVisibility:
866 case CSSPropertyWebkitAppearance:
867 case CSSPropertyWebkitBackfaceVisibility:
868 case CSSPropertyWebkitBorderAfterStyle:
869 case CSSPropertyWebkitBorderBeforeStyle:
870 case CSSPropertyWebkitBorderEndStyle:
871 case CSSPropertyWebkitBorderFit:
872 case CSSPropertyWebkitBorderStartStyle:
873 case CSSPropertyWebkitBoxAlign:
874 case CSSPropertyWebkitBoxDecorationBreak:
875 case CSSPropertyWebkitBoxDirection:
876 case CSSPropertyWebkitBoxLines:
877 case CSSPropertyWebkitBoxOrient:
878 case CSSPropertyWebkitBoxPack:
879 case CSSPropertyInternalCallback:
880 case CSSPropertyWebkitColumnBreakAfter:
881 case CSSPropertyWebkitColumnBreakBefore:
882 case CSSPropertyWebkitColumnBreakInside:
883 case CSSPropertyColumnFill:
884 case CSSPropertyWebkitColumnRuleStyle:
885 case CSSPropertyAlignContent:
886 case CSSPropertyFlexDirection:
887 case CSSPropertyFlexWrap:
888 case CSSPropertyJustifyContent:
889 case CSSPropertyFontKerning:
890 case CSSPropertyWebkitFontSmoothing:
891 case CSSPropertyGridAutoFlow:
892 case CSSPropertyWebkitLineBreak:
893 case CSSPropertyWebkitMarginAfterCollapse:
894 case CSSPropertyWebkitMarginBeforeCollapse:
895 case CSSPropertyWebkitMarginBottomCollapse:
896 case CSSPropertyWebkitMarginTopCollapse:
897 case CSSPropertyInternalMarqueeDirection:
898 case CSSPropertyInternalMarqueeStyle:
899 case CSSPropertyWebkitPrintColorAdjust:
900 case CSSPropertyWebkitRtlOrdering:
901 case CSSPropertyWebkitRubyPosition:
902 case CSSPropertyWebkitTextCombine:
903 case CSSPropertyWebkitTextEmphasisPosition:
904 case CSSPropertyWebkitTextSecurity:
905 case CSSPropertyWebkitTransformStyle:
906 case CSSPropertyWebkitUserDrag:
907 case CSSPropertyWebkitUserModify:
908 case CSSPropertyWebkitUserSelect:
909 case CSSPropertyWebkitWrapFlow:
910 case CSSPropertyWebkitWrapThrough:
911 case CSSPropertyWebkitWritingMode:
912 case CSSPropertyWhiteSpace:
913 case CSSPropertyWordBreak:
914 case CSSPropertyWordWrap:
916 case CSSPropertyAlignItems:
917 case CSSPropertyAlignSelf:
918 return !RuntimeEnabledFeatures::cssGridLayoutEnabled();
924 static bool parseKeywordValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext)
926 ASSERT(!string.isEmpty());
928 if (!isKeywordPropertyID(propertyId)) {
929 // All properties accept the values of "initial" and "inherit".
930 String lowerCaseString = string.lower();
931 if (lowerCaseString != "initial" && lowerCaseString != "inherit")
934 // Parse initial/inherit shorthands using the BisonCSSParser.
935 if (shorthandForProperty(propertyId).length())
939 CSSParserString cssString;
940 cssString.init(string);
941 CSSValueID valueID = cssValueKeywordID(cssString);
946 RefPtr<CSSValue> value;
947 if (valueID == CSSValueInherit)
948 value = cssValuePool().createInheritedValue();
949 else if (valueID == CSSValueInitial)
950 value = cssValuePool().createExplicitInitialValue();
951 else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext))
952 value = cssValuePool().createIdentifierValue(valueID);
956 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
960 template <typename CharType>
961 static bool parseTransformTranslateArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSTransformValue* transformValue)
963 while (expectedCount) {
964 size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
965 if (delimiter == kNotFound)
967 unsigned argumentLength = static_cast<unsigned>(delimiter);
968 CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
970 if (!parseSimpleLength(pos, argumentLength, unit, number))
972 if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER))
974 transformValue->append(cssValuePool().createValue(number, CSSPrimitiveValue::CSS_PX));
975 pos += argumentLength + 1;
981 template <typename CharType>
982 static PassRefPtrWillBeRawPtr<CSSTransformValue> parseTranslateTransformValue(CharType*& pos, CharType* end)
984 static const int shortestValidTransformStringLength = 12;
986 if (end - pos < shortestValidTransformStringLength)
989 if ((pos[0] != 't' && pos[0] != 'T')
990 || (pos[1] != 'r' && pos[1] != 'R')
991 || (pos[2] != 'a' && pos[2] != 'A')
992 || (pos[3] != 'n' && pos[3] != 'N')
993 || (pos[4] != 's' && pos[4] != 'S')
994 || (pos[5] != 'l' && pos[5] != 'L')
995 || (pos[6] != 'a' && pos[6] != 'A')
996 || (pos[7] != 't' && pos[7] != 'T')
997 || (pos[8] != 'e' && pos[8] != 'E'))
1000 CSSTransformValue::TransformOperationType transformType;
1001 unsigned expectedArgumentCount = 1;
1002 unsigned argumentStart = 11;
1003 if ((pos[9] == 'x' || pos[9] == 'X') && pos[10] == '(') {
1004 transformType = CSSTransformValue::TranslateXTransformOperation;
1005 } else if ((pos[9] == 'y' || pos[9] == 'Y') && pos[10] == '(') {
1006 transformType = CSSTransformValue::TranslateYTransformOperation;
1007 } else if ((pos[9] == 'z' || pos[9] == 'Z') && pos[10] == '(') {
1008 transformType = CSSTransformValue::TranslateZTransformOperation;
1009 } else if (pos[9] == '(') {
1010 transformType = CSSTransformValue::TranslateTransformOperation;
1011 expectedArgumentCount = 2;
1013 } else if (pos[9] == '3' && (pos[10] == 'd' || pos[10] == 'D') && pos[11] == '(') {
1014 transformType = CSSTransformValue::Translate3DTransformOperation;
1015 expectedArgumentCount = 3;
1020 pos += argumentStart;
1022 RefPtrWillBeRawPtr<CSSTransformValue> transformValue = CSSTransformValue::create(transformType);
1023 if (!parseTransformTranslateArguments(pos, end, expectedArgumentCount, transformValue.get()))
1025 return transformValue.release();
1028 template <typename CharType>
1029 static PassRefPtrWillBeRawPtr<CSSValueList> parseTranslateTransformList(CharType*& pos, CharType* end)
1031 RefPtrWillBeRawPtr<CSSValueList> transformList;
1033 while (pos < end && isCSSSpace(*pos))
1035 RefPtrWillBeRawPtr<CSSTransformValue> transformValue = parseTranslateTransformValue(pos, end);
1036 if (!transformValue)
1039 transformList = CSSValueList::createSpaceSeparated();
1040 transformList->append(transformValue.release());
1042 if (isCSSSpace(*pos))
1046 return transformList.release();
1049 static bool parseTranslateTransform(MutableStylePropertySet* properties, CSSPropertyID propertyID, const String& string, bool important)
1051 if (propertyID != CSSPropertyWebkitTransform)
1053 if (string.isEmpty())
1055 RefPtrWillBeRawPtr<CSSValueList> transformList;
1056 if (string.is8Bit()) {
1057 const LChar* pos = string.characters8();
1058 const LChar* end = pos + string.length();
1059 transformList = parseTranslateTransformList(pos, end);
1063 const UChar* pos = string.characters16();
1064 const UChar* end = pos + string.length();
1065 transformList = parseTranslateTransformList(pos, end);
1069 properties->addParsedProperty(CSSProperty(CSSPropertyWebkitTransform, transformList.release(), important));
1073 PassRefPtrWillBeRawPtr<CSSValueList> BisonCSSParser::parseFontFaceValue(const AtomicString& string)
1075 if (string.isEmpty())
1077 RefPtr<MutableStylePropertySet> dummyStyle = MutableStylePropertySet::create();
1078 if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, HTMLQuirksMode, 0))
1081 RefPtr<CSSValue> fontFamily = dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily);
1082 if (!fontFamily->isValueList())
1085 return toCSSValueList(dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily).get());
1088 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationTimingFunctionValue(const String& string)
1090 if (string.isEmpty())
1092 RefPtr<MutableStylePropertySet> style = MutableStylePropertySet::create();
1093 if (!parseValue(style.get(), CSSPropertyAnimationTimingFunction, string, false, HTMLStandardMode, 0))
1096 return style->getPropertyCSSValue(CSSPropertyAnimationTimingFunction);
1099 bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, const Document& document)
1101 ASSERT(!string.isEmpty());
1103 CSSParserContext context(document, UseCounter::getFrom(&document));
1105 if (parseSimpleLengthValue(declaration, propertyID, string, important, context.mode()))
1107 if (parseColorValue(declaration, propertyID, string, important, context.mode()))
1109 if (parseKeywordValue(declaration, propertyID, string, important, context))
1112 BisonCSSParser parser(context);
1113 return parser.parseValue(declaration, propertyID, string, important, static_cast<StyleSheetContents*>(0));
1116 bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
1118 ASSERT(!string.isEmpty());
1119 if (parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode))
1121 if (parseColorValue(declaration, propertyID, string, important, cssParserMode))
1124 CSSParserContext context(cssParserMode, 0);
1125 if (contextStyleSheet) {
1126 context = contextStyleSheet->parserContext();
1127 context.setMode(cssParserMode);
1130 if (parseKeywordValue(declaration, propertyID, string, important, context))
1132 if (parseTranslateTransform(declaration, propertyID, string, important))
1135 BisonCSSParser parser(context);
1136 return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet);
1139 bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet)
1141 // FIXME: Check RuntimeCSSEnabled::isPropertyEnabled or isValueEnabledForProperty.
1143 if (m_context.useCounter())
1144 m_context.useCounter()->count(m_context, propertyID);
1146 setStyleSheet(contextStyleSheet);
1148 setupParser("@-internal-value ", string, "");
1151 m_important = important;
1154 StyleDeclarationScope scope(this, declaration);
1159 m_id = CSSPropertyInvalid;
1162 if (m_hasFontFaceOnlyValues)
1163 deleteFontFaceOnlyValues();
1164 if (!m_parsedProperties.isEmpty()) {
1166 declaration->addParsedProperties(m_parsedProperties);
1173 // The color will only be changed when string contains a valid CSS color, so callers
1174 // can set it to a default color and ignore the boolean result.
1175 bool BisonCSSParser::parseColor(RGBA32& color, const String& string, bool strict)
1177 // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
1178 if (fastParseColor(color, string, strict))
1181 BisonCSSParser parser(strictCSSParserContext());
1183 // In case the fast-path parser didn't understand the color, try the full parser.
1184 if (!parser.parseColor(string))
1187 CSSValue* value = parser.m_parsedProperties.first().value();
1188 if (!value->isPrimitiveValue())
1191 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
1192 if (!primitiveValue->isRGBColor())
1195 color = primitiveValue->getRGBA32Value();
1199 bool BisonCSSParser::parseColor(const String& string)
1201 setupParser("@-internal-decls color:", string, "");
1205 return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor;
1208 // FIXME: This is copied from SVGCSSParser.cpp
1209 static bool isSystemColor(int id)
1211 return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu;
1214 bool BisonCSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document)
1219 CSSParserString cssColor;
1220 cssColor.init(string);
1221 CSSValueID id = cssValueKeywordID(cssColor);
1222 if (!isSystemColor(id))
1225 Color parsedColor = RenderTheme::theme().systemColor(id);
1226 color = parsedColor.rgb();
1230 void BisonCSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
1232 m_selectorListForParseSelector = &selectorList;
1234 setupParser("@-internal-selector ", string, "");
1238 m_selectorListForParseSelector = 0;
1241 PassRefPtr<ImmutableStylePropertySet> BisonCSSParser::parseInlineStyleDeclaration(const String& string, Element* element)
1243 Document& document = element->document();
1244 CSSParserContext context = CSSParserContext(document.elementSheet()->contents()->parserContext(), UseCounter::getFrom(&document));
1245 context.setMode((element->isHTMLElement() && !document.inQuirksMode()) ? HTMLStandardMode : HTMLQuirksMode);
1246 return BisonCSSParser(context).parseDeclaration(string, document.elementSheet()->contents());
1249 PassRefPtr<ImmutableStylePropertySet> BisonCSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet)
1251 setStyleSheet(contextStyleSheet);
1253 setupParser("@-internal-decls ", string, "");
1257 if (m_hasFontFaceOnlyValues)
1258 deleteFontFaceOnlyValues();
1260 RefPtr<ImmutableStylePropertySet> style = createStylePropertySet();
1262 return style.release();
1266 bool BisonCSSParser::parseDeclaration(MutableStylePropertySet* declaration, const String& string, CSSParserObserver* observer, StyleSheetContents* contextStyleSheet)
1268 setStyleSheet(contextStyleSheet);
1270 TemporaryChange<CSSParserObserver*> scopedObsever(m_observer, observer);
1272 setupParser("@-internal-decls ", string, "");
1274 m_observer->startRuleHeader(CSSRuleSourceData::STYLE_RULE, 0);
1275 m_observer->endRuleHeader(1);
1276 m_observer->startRuleBody(0);
1280 StyleDeclarationScope scope(this, declaration);
1287 if (m_hasFontFaceOnlyValues)
1288 deleteFontFaceOnlyValues();
1289 if (!m_parsedProperties.isEmpty()) {
1291 declaration->addParsedProperties(m_parsedProperties);
1296 m_observer->endRuleBody(string.length(), false);
1301 PassRefPtr<MediaQuerySet> BisonCSSParser::parseMediaQueryList(const String& string)
1303 ASSERT(!m_mediaList);
1305 // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
1306 // instead insert one " " (which is caught by maybe_space in CSSGrammar.y)
1307 setupParser("@-internal-medialist ", string, "");
1310 ASSERT(m_mediaList);
1311 return m_mediaList.release();
1314 static inline void filterProperties(bool important, const BisonCSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties)
1316 // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
1317 for (int i = input.size() - 1; i >= 0; --i) {
1318 const CSSProperty& property = input[i];
1319 if (property.isImportant() != important)
1321 const unsigned propertyIDIndex = property.id() - firstCSSProperty;
1322 if (seenProperties.get(propertyIDIndex))
1324 seenProperties.set(propertyIDIndex);
1325 output[--unusedEntries] = property;
1329 PassRefPtr<ImmutableStylePropertySet> BisonCSSParser::createStylePropertySet()
1331 BitArray<numCSSProperties> seenProperties;
1332 size_t unusedEntries = m_parsedProperties.size();
1333 Vector<CSSProperty, 256> results(unusedEntries);
1335 // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found.
1336 filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties);
1337 filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties);
1339 results.remove(0, unusedEntries);
1341 CSSParserMode mode = inViewport() ? CSSViewportRuleMode : m_context.mode();
1343 return ImmutableStylePropertySet::create(results.data(), results.size(), mode);
1346 void BisonCSSParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
1348 RefPtr<CSSValue> val = value.get();
1349 addProperty(propId, value, important, implicit);
1351 CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId);
1352 if (prefixingVariant == propId)
1355 if (m_currentShorthand) {
1356 // We can't use ShorthandScope here as we can already be inside one (e.g we are parsing CSSTransition).
1357 m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
1358 addProperty(prefixingVariant, val.release(), important, implicit);
1359 m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
1361 addProperty(prefixingVariant, val.release(), important, implicit);
1365 void BisonCSSParser::addProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
1367 // This property doesn't belong to a shorthand.
1368 if (!m_currentShorthand) {
1369 m_parsedProperties.append(CSSProperty(propId, value, important, false, CSSPropertyInvalid, m_implicitShorthand || implicit));
1373 Vector<StylePropertyShorthand, 4> shorthands;
1374 getMatchingShorthandsForLonghand(propId, &shorthands);
1375 // The longhand does not belong to multiple shorthands.
1376 if (shorthands.size() == 1)
1377 m_parsedProperties.append(CSSProperty(propId, value, important, true, CSSPropertyInvalid, m_implicitShorthand || implicit));
1379 m_parsedProperties.append(CSSProperty(propId, value, important, true, indexOfShorthandForLonghand(m_currentShorthand, shorthands), m_implicitShorthand || implicit));
1382 void BisonCSSParser::rollbackLastProperties(int num)
1385 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
1386 m_parsedProperties.shrink(m_parsedProperties.size() - num);
1389 void BisonCSSParser::clearProperties()
1391 m_parsedProperties.clear();
1392 m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
1393 m_hasFontFaceOnlyValues = false;
1396 KURL BisonCSSParser::completeURL(const String& url) const
1398 return m_context.completeURL(url);
1401 bool BisonCSSParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc)
1403 bool mustBeNonNegative = unitflags & FNonNeg;
1405 if (!parseCalculation(value, mustBeNonNegative ? ValueRangeNonNegative : ValueRangeAll))
1409 switch (m_parsedCalculation->category()) {
1411 b = (unitflags & FLength);
1414 b = (unitflags & FPercent);
1415 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1419 b = (unitflags & FNumber);
1420 if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
1422 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1425 case CalcPercentLength:
1426 b = (unitflags & FPercent) && (unitflags & FLength);
1428 case CalcPercentNumber:
1429 b = (unitflags & FPercent) && (unitflags & FNumber);
1434 if (!b || releaseCalc == ReleaseParsedCalcValue)
1435 m_parsedCalculation.release();
1439 inline bool BisonCSSParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
1441 // Quirks mode and presentation attributes accept unit less values.
1442 return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || isUnitLessLengthParsingEnabledForMode(cssParserMode));
1445 bool BisonCSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
1447 if (isCalculation(value))
1448 return validCalculationUnit(value, unitflags, releaseCalc);
1451 switch (value->unit) {
1452 case CSSPrimitiveValue::CSS_NUMBER:
1453 b = (unitflags & FNumber);
1454 if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
1455 value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
1456 ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
1459 if (!b && (unitflags & FInteger) && value->isInt)
1461 if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0)
1464 case CSSPrimitiveValue::CSS_PERCENTAGE:
1465 b = (unitflags & FPercent);
1467 case CSSParserValue::Q_EMS:
1468 case CSSPrimitiveValue::CSS_EMS:
1469 case CSSPrimitiveValue::CSS_REMS:
1470 case CSSPrimitiveValue::CSS_CHS:
1471 case CSSPrimitiveValue::CSS_EXS:
1472 case CSSPrimitiveValue::CSS_PX:
1473 case CSSPrimitiveValue::CSS_CM:
1474 case CSSPrimitiveValue::CSS_MM:
1475 case CSSPrimitiveValue::CSS_IN:
1476 case CSSPrimitiveValue::CSS_PT:
1477 case CSSPrimitiveValue::CSS_PC:
1478 case CSSPrimitiveValue::CSS_VW:
1479 case CSSPrimitiveValue::CSS_VH:
1480 case CSSPrimitiveValue::CSS_VMIN:
1481 case CSSPrimitiveValue::CSS_VMAX:
1482 b = (unitflags & FLength);
1484 case CSSPrimitiveValue::CSS_MS:
1485 case CSSPrimitiveValue::CSS_S:
1486 b = (unitflags & FTime);
1488 case CSSPrimitiveValue::CSS_DEG:
1489 case CSSPrimitiveValue::CSS_RAD:
1490 case CSSPrimitiveValue::CSS_GRAD:
1491 case CSSPrimitiveValue::CSS_TURN:
1492 b = (unitflags & FAngle);
1494 case CSSPrimitiveValue::CSS_DPPX:
1495 case CSSPrimitiveValue::CSS_DPI:
1496 case CSSPrimitiveValue::CSS_DPCM:
1497 b = (unitflags & FResolution);
1499 case CSSPrimitiveValue::CSS_HZ:
1500 case CSSPrimitiveValue::CSS_KHZ:
1501 case CSSPrimitiveValue::CSS_DIMENSION:
1505 if (b && unitflags & FNonNeg && value->fValue < 0)
1510 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> BisonCSSParser::createPrimitiveNumericValue(CSSParserValue* value)
1512 if (m_parsedCalculation) {
1513 ASSERT(isCalculation(value));
1514 return CSSPrimitiveValue::create(m_parsedCalculation.release());
1517 ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1518 || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
1519 || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
1520 || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
1521 return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
1524 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> BisonCSSParser::createPrimitiveStringValue(CSSParserValue* value)
1526 ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
1527 return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
1530 static inline bool isComma(CSSParserValue* value)
1532 return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
1535 static inline bool isForwardSlashOperator(CSSParserValue* value)
1538 return value->unit == CSSParserValue::Operator && value->iValue == '/';
1541 static bool isGeneratedImageValue(CSSParserValue* val)
1543 if (val->unit != CSSParserValue::Function)
1546 return equalIgnoringCase(val->function->name, "-webkit-gradient(")
1547 || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
1548 || equalIgnoringCase(val->function->name, "linear-gradient(")
1549 || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
1550 || equalIgnoringCase(val->function->name, "repeating-linear-gradient(")
1551 || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
1552 || equalIgnoringCase(val->function->name, "radial-gradient(")
1553 || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
1554 || equalIgnoringCase(val->function->name, "repeating-radial-gradient(")
1555 || equalIgnoringCase(val->function->name, "-webkit-canvas(")
1556 || equalIgnoringCase(val->function->name, "-webkit-cross-fade(");
1559 bool BisonCSSParser::validWidthOrHeight(CSSParserValue* value)
1562 if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
1564 return !id && validUnit(value, FLength | FPercent | FNonNeg);
1567 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> BisonCSSParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value)
1570 return cssValuePool().createIdentifierValue(identifier);
1571 if (value->unit == CSSPrimitiveValue::CSS_STRING)
1572 return createPrimitiveStringValue(value);
1573 if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1574 return createPrimitiveNumericValue(value);
1575 if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
1576 return createPrimitiveNumericValue(value);
1577 if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
1578 return createPrimitiveNumericValue(value);
1579 if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
1580 return createPrimitiveNumericValue(value);
1581 if (value->unit >= CSSParserValue::Q_EMS)
1582 return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
1583 if (isCalculation(value))
1584 return CSSPrimitiveValue::create(m_parsedCalculation.release());
1589 void BisonCSSParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtr<CSSValue> prpValue, bool important)
1591 const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
1592 unsigned shorthandLength = shorthand.length();
1593 if (!shorthandLength) {
1594 addProperty(propId, prpValue, important);
1598 RefPtr<CSSValue> value = prpValue;
1599 ShorthandScope scope(this, propId);
1600 const CSSPropertyID* longhands = shorthand.properties();
1601 for (unsigned i = 0; i < shorthandLength; ++i)
1602 addProperty(longhands[i], value, important);
1605 void BisonCSSParser::setCurrentProperty(CSSPropertyID propId)
1610 bool BisonCSSParser::parseValue(CSSPropertyID propId, bool important)
1612 if (!isInternalPropertyAndValueParsingEnabledForMode(m_context.mode()) && isInternalProperty(propId))
1615 // We don't count the UA style sheet in our statistics.
1616 if (m_context.useCounter())
1617 m_context.useCounter()->count(m_context, propId);
1622 CSSParserValue* value = m_valueList->current();
1628 // Allow @viewport rules from UA stylesheets even if the feature is disabled.
1629 if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode()))
1632 return parseViewportProperty(propId, important);
1635 // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
1636 // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
1637 ASSERT(!m_parsedCalculation);
1639 CSSValueID id = value->id;
1641 int num = inShorthand() ? 1 : m_valueList->size();
1643 if (id == CSSValueInherit) {
1646 addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important);
1649 else if (id == CSSValueInitial) {
1652 addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important);
1656 if (isKeywordPropertyID(propId)) {
1657 if (!isValidKeywordPropertyAndValue(propId, id, m_context))
1659 if (m_valueList->next() && !inShorthand())
1661 addProperty(propId, cssValuePool().createIdentifierValue(id), important);
1665 bool validPrimitive = false;
1666 RefPtr<CSSValue> parsedValue;
1669 case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
1670 return parseSize(propId, important);
1672 case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit
1674 validPrimitive = true;
1676 return parseQuotes(propId, important);
1678 case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | isolate-override | plaintext | inherit
1679 if (id == CSSValueNormal
1680 || id == CSSValueEmbed
1681 || id == CSSValueBidiOverride
1682 || id == CSSValueWebkitIsolate
1683 || id == CSSValueWebkitIsolateOverride
1684 || id == CSSValueWebkitPlaintext)
1685 validPrimitive = true;
1688 case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
1689 // close-quote | no-open-quote | no-close-quote ]+ | inherit
1690 return parseContent(propId, important);
1692 case CSSPropertyClip: // <shape> | auto | inherit
1693 if (id == CSSValueAuto)
1694 validPrimitive = true;
1695 else if (value->unit == CSSParserValue::Function)
1696 return parseClipShape(propId, important);
1699 /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
1700 * correctly and allows optimization in WebCore::applyRule(..)
1702 case CSSPropertyOverflow: {
1703 ShorthandScope scope(this, propId);
1704 if (num != 1 || !parseValue(CSSPropertyOverflowY, important))
1707 RefPtr<CSSValue> overflowXValue;
1709 // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been
1710 // set using the shorthand, then for now overflow-x will default to auto, but once we implement
1711 // pagination controls, it should default to hidden. If the overflow-y value is anything but
1712 // paged-x or paged-y, then overflow-x and overflow-y should have the same value.
1713 if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
1714 overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
1716 overflowXValue = m_parsedProperties.last().value();
1717 addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
1721 case CSSPropertyTextAlign:
1722 // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
1723 // | start | end | <string> | inherit | -webkit-auto (converted to start)
1724 if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
1725 || value->unit == CSSPrimitiveValue::CSS_STRING)
1726 validPrimitive = true;
1729 case CSSPropertyFontWeight: { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
1730 if (m_valueList->size() != 1)
1732 return parseFontWeight(important);
1734 case CSSPropertyBorderSpacing: {
1736 ShorthandScope scope(this, CSSPropertyBorderSpacing);
1737 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
1739 CSSValue* value = m_parsedProperties.last().value();
1740 addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
1743 else if (num == 2) {
1744 ShorthandScope scope(this, CSSPropertyBorderSpacing);
1745 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
1751 case CSSPropertyWebkitBorderHorizontalSpacing:
1752 case CSSPropertyWebkitBorderVerticalSpacing:
1753 validPrimitive = validUnit(value, FLength | FNonNeg);
1755 case CSSPropertyOutlineColor: // <color> | invert | inherit
1756 // Outline color has "invert" as additional keyword.
1757 // Also, we want to allow the special focus color even in HTML Standard parsing mode.
1758 if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
1759 validPrimitive = true;
1763 case CSSPropertyBackgroundColor: // <color> | inherit
1764 case CSSPropertyBorderTopColor: // <color> | inherit
1765 case CSSPropertyBorderRightColor:
1766 case CSSPropertyBorderBottomColor:
1767 case CSSPropertyBorderLeftColor:
1768 case CSSPropertyWebkitBorderStartColor:
1769 case CSSPropertyWebkitBorderEndColor:
1770 case CSSPropertyWebkitBorderBeforeColor:
1771 case CSSPropertyWebkitBorderAfterColor:
1772 case CSSPropertyColor: // <color> | inherit
1773 case CSSPropertyTextDecorationColor: // CSS3 text decoration colors
1774 case CSSPropertyTextLineThroughColor:
1775 case CSSPropertyTextUnderlineColor:
1776 case CSSPropertyTextOverlineColor:
1777 case CSSPropertyWebkitColumnRuleColor:
1778 case CSSPropertyWebkitTextEmphasisColor:
1779 case CSSPropertyWebkitTextFillColor:
1780 case CSSPropertyWebkitTextStrokeColor:
1781 if (propId == CSSPropertyTextDecorationColor
1782 && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
1785 if ((id >= CSSValueAqua && id <= CSSValueWebkitText) || id == CSSValueMenu) {
1786 validPrimitive = isValueAllowedInMode(id, m_context.mode());
1788 parsedValue = parseColor();
1790 m_valueList->next();
1794 case CSSPropertyCursor: {
1795 // Grammar defined by CSS3 UI and modified by CSS4 images:
1796 // [ [<image> [<x> <y>]?,]*
1797 // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
1798 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
1799 // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
1800 // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
1801 // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
1802 RefPtrWillBeRawPtr<CSSValueList> list;
1804 RefPtr<CSSValue> image = 0;
1805 if (value->unit == CSSPrimitiveValue::CSS_URI) {
1806 String uri = value->string;
1808 image = CSSImageValue::create(completeURL(uri));
1809 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
1810 image = parseImageSet(m_valueList.get());
1817 value = m_valueList->next();
1818 while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
1819 coords.append(int(value->fValue));
1820 value = m_valueList->next();
1822 bool hasHotSpot = false;
1823 IntPoint hotSpot(-1, -1);
1824 int nrcoords = coords.size();
1825 if (nrcoords > 0 && nrcoords != 2)
1827 if (nrcoords == 2) {
1829 hotSpot = IntPoint(coords[0], coords[1]);
1833 list = CSSValueList::createCommaSeparated();
1836 list->append(CSSCursorImageValue::create(image, hasHotSpot, hotSpot));
1838 if (!value || !(value->unit == CSSParserValue::Operator && value->iValue == ','))
1840 value = m_valueList->next(); // comma
1845 if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
1846 list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
1847 else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
1848 list->append(cssValuePool().createIdentifierValue(value->id));
1849 m_valueList->next();
1850 parsedValue = list.release();
1854 if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
1855 id = CSSValuePointer;
1856 validPrimitive = true;
1857 } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
1858 validPrimitive = true;
1860 ASSERT_NOT_REACHED();
1866 case CSSPropertyBackgroundBlendMode:
1867 case CSSPropertyBackgroundAttachment:
1868 case CSSPropertyBackgroundClip:
1869 case CSSPropertyWebkitBackgroundClip:
1870 case CSSPropertyWebkitBackgroundComposite:
1871 case CSSPropertyBackgroundImage:
1872 case CSSPropertyBackgroundOrigin:
1873 case CSSPropertyMaskSourceType:
1874 case CSSPropertyWebkitBackgroundOrigin:
1875 case CSSPropertyBackgroundPosition:
1876 case CSSPropertyBackgroundPositionX:
1877 case CSSPropertyBackgroundPositionY:
1878 case CSSPropertyBackgroundSize:
1879 case CSSPropertyWebkitBackgroundSize:
1880 case CSSPropertyBackgroundRepeat:
1881 case CSSPropertyBackgroundRepeatX:
1882 case CSSPropertyBackgroundRepeatY:
1883 case CSSPropertyWebkitMaskClip:
1884 case CSSPropertyWebkitMaskComposite:
1885 case CSSPropertyWebkitMaskImage:
1886 case CSSPropertyWebkitMaskOrigin:
1887 case CSSPropertyWebkitMaskPosition:
1888 case CSSPropertyWebkitMaskPositionX:
1889 case CSSPropertyWebkitMaskPositionY:
1890 case CSSPropertyWebkitMaskSize:
1891 case CSSPropertyWebkitMaskRepeat:
1892 case CSSPropertyWebkitMaskRepeatX:
1893 case CSSPropertyWebkitMaskRepeatY:
1895 RefPtr<CSSValue> val1;
1896 RefPtr<CSSValue> val2;
1897 CSSPropertyID propId1, propId2;
1898 bool result = false;
1899 if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
1900 OwnPtr<ShorthandScope> shorthandScope;
1901 if (propId == CSSPropertyBackgroundPosition ||
1902 propId == CSSPropertyBackgroundRepeat ||
1903 propId == CSSPropertyWebkitMaskPosition ||
1904 propId == CSSPropertyWebkitMaskRepeat) {
1905 shorthandScope = adoptPtr(new ShorthandScope(this, propId));
1907 addProperty(propId1, val1.release(), important);
1909 addProperty(propId2, val2.release(), important);
1912 m_implicitShorthand = false;
1915 case CSSPropertyObjectPosition:
1916 return RuntimeEnabledFeatures::objectFitPositionEnabled() && parseObjectPosition(important);
1917 case CSSPropertyListStyleImage: // <uri> | none | inherit
1918 case CSSPropertyBorderImageSource:
1919 case CSSPropertyWebkitMaskBoxImageSource:
1920 if (id == CSSValueNone) {
1921 parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
1922 m_valueList->next();
1923 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
1924 parsedValue = CSSImageValue::create(completeURL(value->string));
1925 m_valueList->next();
1926 } else if (isGeneratedImageValue(value)) {
1927 if (parseGeneratedImage(m_valueList.get(), parsedValue))
1928 m_valueList->next();
1932 else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
1933 parsedValue = parseImageSet(m_valueList.get());
1936 m_valueList->next();
1940 case CSSPropertyWebkitTextStrokeWidth:
1941 case CSSPropertyOutlineWidth: // <border-width> | inherit
1942 case CSSPropertyBorderTopWidth: //// <border-width> | inherit
1943 case CSSPropertyBorderRightWidth: // Which is defined as
1944 case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
1945 case CSSPropertyBorderLeftWidth:
1946 case CSSPropertyWebkitBorderStartWidth:
1947 case CSSPropertyWebkitBorderEndWidth:
1948 case CSSPropertyWebkitBorderBeforeWidth:
1949 case CSSPropertyWebkitBorderAfterWidth:
1950 case CSSPropertyWebkitColumnRuleWidth:
1951 if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
1952 validPrimitive = true;
1954 validPrimitive = validUnit(value, FLength | FNonNeg);
1957 case CSSPropertyLetterSpacing: // normal | <length> | inherit
1958 case CSSPropertyWordSpacing: // normal | <length> | inherit
1959 if (id == CSSValueNormal)
1960 validPrimitive = true;
1962 validPrimitive = validUnit(value, FLength);
1965 case CSSPropertyTextIndent:
1966 parsedValue = parseTextIndent();
1969 case CSSPropertyPaddingTop: //// <padding-width> | inherit
1970 case CSSPropertyPaddingRight: // Which is defined as
1971 case CSSPropertyPaddingBottom: // <length> | <percentage>
1972 case CSSPropertyPaddingLeft: ////
1973 case CSSPropertyWebkitPaddingStart:
1974 case CSSPropertyWebkitPaddingEnd:
1975 case CSSPropertyWebkitPaddingBefore:
1976 case CSSPropertyWebkitPaddingAfter:
1977 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
1980 case CSSPropertyMaxWidth:
1981 case CSSPropertyWebkitMaxLogicalWidth:
1982 case CSSPropertyMaxHeight:
1983 case CSSPropertyWebkitMaxLogicalHeight:
1984 validPrimitive = (id == CSSValueNone || validWidthOrHeight(value));
1987 case CSSPropertyMinWidth:
1988 case CSSPropertyWebkitMinLogicalWidth:
1989 case CSSPropertyMinHeight:
1990 case CSSPropertyWebkitMinLogicalHeight:
1991 validPrimitive = validWidthOrHeight(value);
1994 case CSSPropertyWidth:
1995 case CSSPropertyWebkitLogicalWidth:
1996 case CSSPropertyHeight:
1997 case CSSPropertyWebkitLogicalHeight:
1998 validPrimitive = (id == CSSValueAuto || validWidthOrHeight(value));
2001 case CSSPropertyFontSize:
2002 return parseFontSize(important);
2004 case CSSPropertyFontVariant: // normal | small-caps | inherit
2005 return parseFontVariant(important);
2007 case CSSPropertyVerticalAlign:
2008 // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
2009 // <percentage> | <length> | inherit
2011 if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
2012 validPrimitive = true;
2014 validPrimitive = (!id && validUnit(value, FLength | FPercent));
2017 case CSSPropertyBottom: // <length> | <percentage> | auto | inherit
2018 case CSSPropertyLeft: // <length> | <percentage> | auto | inherit
2019 case CSSPropertyRight: // <length> | <percentage> | auto | inherit
2020 case CSSPropertyTop: // <length> | <percentage> | auto | inherit
2021 case CSSPropertyMarginTop: //// <margin-width> | inherit
2022 case CSSPropertyMarginRight: // Which is defined as
2023 case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit
2024 case CSSPropertyMarginLeft: ////
2025 case CSSPropertyWebkitMarginStart:
2026 case CSSPropertyWebkitMarginEnd:
2027 case CSSPropertyWebkitMarginBefore:
2028 case CSSPropertyWebkitMarginAfter:
2029 if (id == CSSValueAuto)
2030 validPrimitive = true;
2032 validPrimitive = (!id && validUnit(value, FLength | FPercent));
2035 case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
2036 case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
2037 if (id == CSSValueAuto)
2038 validPrimitive = true;
2040 validPrimitive = (!id && validUnit(value, FPositiveInteger, HTMLQuirksMode));
2043 case CSSPropertyZIndex: // auto | <integer> | inherit
2044 if (id == CSSValueAuto)
2045 validPrimitive = true;
2047 validPrimitive = (!id && validUnit(value, FInteger, HTMLQuirksMode));
2050 case CSSPropertyLineHeight:
2051 return parseLineHeight(important);
2052 case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
2053 if (id != CSSValueNone)
2054 return parseCounter(propId, 1, important);
2055 validPrimitive = true;
2057 case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit
2058 if (id != CSSValueNone)
2059 return parseCounter(propId, 0, important);
2060 validPrimitive = true;
2062 case CSSPropertyFontFamily:
2063 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
2065 parsedValue = parseFontFamily();
2069 case CSSPropertyTextDecoration:
2070 // Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration
2071 // is disabled to match CSS 2.1 rules for parsing 'text-decoration'.
2072 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) {
2073 // [ <text-decoration-line> || <text-decoration-style> || <text-decoration-color> ] | inherit
2074 return parseShorthand(CSSPropertyTextDecoration, textDecorationShorthand(), important);
2076 case CSSPropertyWebkitTextDecorationsInEffect:
2077 case CSSPropertyTextDecorationLine:
2078 // none | [ underline || overline || line-through || blink ] | inherit
2079 return parseTextDecoration(propId, important);
2081 case CSSPropertyTextDecorationStyle:
2082 // solid | double | dotted | dashed | wavy
2083 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()
2084 && (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDotted || id == CSSValueDashed || id == CSSValueWavy))
2085 validPrimitive = true;
2088 case CSSPropertyTextUnderlinePosition:
2089 // auto | under | inherit
2090 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled())
2091 return parseTextUnderlinePosition(important);
2094 case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit
2095 if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
2096 validPrimitive = true;
2098 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode));
2101 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.
2102 return parseFontFaceSrc();
2104 case CSSPropertyUnicodeRange:
2105 return parseFontFaceUnicodeRange();
2107 /* CSS3 properties */
2109 case CSSPropertyBorderImage:
2110 case CSSPropertyWebkitMaskBoxImage:
2111 return parseBorderImageShorthand(propId, important);
2112 case CSSPropertyWebkitBorderImage: {
2113 if (RefPtr<CSSValue> result = parseBorderImage(propId)) {
2114 addProperty(propId, result, important);
2120 case CSSPropertyBorderImageOutset:
2121 case CSSPropertyWebkitMaskBoxImageOutset: {
2122 RefPtrWillBeRawPtr<CSSPrimitiveValue> result;
2123 if (parseBorderImageOutset(result)) {
2124 addProperty(propId, result, important);
2129 case CSSPropertyBorderImageRepeat:
2130 case CSSPropertyWebkitMaskBoxImageRepeat: {
2131 RefPtr<CSSValue> result;
2132 if (parseBorderImageRepeat(result)) {
2133 addProperty(propId, result, important);
2138 case CSSPropertyBorderImageSlice:
2139 case CSSPropertyWebkitMaskBoxImageSlice: {
2140 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> result;
2141 if (parseBorderImageSlice(propId, result)) {
2142 addProperty(propId, result, important);
2147 case CSSPropertyBorderImageWidth:
2148 case CSSPropertyWebkitMaskBoxImageWidth: {
2149 RefPtrWillBeRawPtr<CSSPrimitiveValue> result;
2150 if (parseBorderImageWidth(result)) {
2151 addProperty(propId, result, important);
2156 case CSSPropertyBorderTopRightRadius:
2157 case CSSPropertyBorderTopLeftRadius:
2158 case CSSPropertyBorderBottomLeftRadius:
2159 case CSSPropertyBorderBottomRightRadius: {
2160 if (num != 1 && num != 2)
2162 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2163 if (!validPrimitive)
2165 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
2166 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2;
2168 value = m_valueList->next();
2169 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2170 if (!validPrimitive)
2172 parsedValue2 = createPrimitiveNumericValue(value);
2174 parsedValue2 = parsedValue1;
2176 addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important);
2179 case CSSPropertyTabSize:
2180 validPrimitive = validUnit(value, FInteger | FNonNeg);
2182 case CSSPropertyWebkitAspectRatio:
2183 return parseAspectRatio(important);
2184 case CSSPropertyBorderRadius:
2185 case CSSPropertyWebkitBorderRadius:
2186 return parseBorderRadius(propId, important);
2187 case CSSPropertyOutlineOffset:
2188 validPrimitive = validUnit(value, FLength);
2190 case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
2191 case CSSPropertyBoxShadow:
2192 case CSSPropertyWebkitBoxShadow:
2193 if (id == CSSValueNone)
2194 validPrimitive = true;
2196 RefPtrWillBeRawPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
2197 if (shadowValueList) {
2198 addProperty(propId, shadowValueList.release(), important);
2199 m_valueList->next();
2205 case CSSPropertyWebkitBoxReflect:
2206 if (id == CSSValueNone)
2207 validPrimitive = true;
2209 return parseReflect(propId, important);
2211 case CSSPropertyOpacity:
2212 validPrimitive = validUnit(value, FNumber);
2214 case CSSPropertyWebkitBoxFlex:
2215 validPrimitive = validUnit(value, FNumber);
2217 case CSSPropertyWebkitBoxFlexGroup:
2218 validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode);
2220 case CSSPropertyWebkitBoxOrdinalGroup:
2221 validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode) && value->fValue;
2223 case CSSPropertyWebkitFilter:
2224 if (id == CSSValueNone)
2225 validPrimitive = true;
2227 RefPtr<CSSValue> val = parseFilter();
2229 addProperty(propId, val, important);
2235 case CSSPropertyFlex: {
2236 ShorthandScope scope(this, propId);
2237 if (id == CSSValueNone) {
2238 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
2239 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
2240 addProperty(CSSPropertyFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
2243 return parseFlex(m_valueList.get(), important);
2245 case CSSPropertyFlexBasis:
2246 // FIXME: Support intrinsic dimensions too.
2247 if (id == CSSValueAuto)
2248 validPrimitive = true;
2250 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
2252 case CSSPropertyFlexGrow:
2253 case CSSPropertyFlexShrink:
2254 validPrimitive = validUnit(value, FNumber | FNonNeg);
2256 case CSSPropertyOrder:
2257 validPrimitive = validUnit(value, FInteger, HTMLStandardMode);
2259 case CSSPropertyInternalMarqueeIncrement:
2260 if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
2261 validPrimitive = true;
2263 validPrimitive = validUnit(value, FLength | FPercent);
2265 case CSSPropertyInternalMarqueeRepetition:
2266 if (id == CSSValueInfinite)
2267 validPrimitive = true;
2269 validPrimitive = validUnit(value, FInteger | FNonNeg);
2271 case CSSPropertyInternalMarqueeSpeed:
2272 if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
2273 validPrimitive = true;
2275 validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
2277 case CSSPropertyWebkitTransform:
2278 if (id == CSSValueNone)
2279 validPrimitive = true;
2281 RefPtr<CSSValue> transformValue = parseTransform();
2282 if (transformValue) {
2283 addProperty(propId, transformValue.release(), important);
2289 case CSSPropertyWebkitTransformOrigin:
2290 case CSSPropertyWebkitTransformOriginX:
2291 case CSSPropertyWebkitTransformOriginY:
2292 case CSSPropertyWebkitTransformOriginZ: {
2293 RefPtr<CSSValue> val1;
2294 RefPtr<CSSValue> val2;
2295 RefPtr<CSSValue> val3;
2296 CSSPropertyID propId1, propId2, propId3;
2297 if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
2298 addProperty(propId1, val1.release(), important);
2300 addProperty(propId2, val2.release(), important);
2302 addProperty(propId3, val3.release(), important);
2307 case CSSPropertyWebkitPerspective:
2308 if (id == CSSValueNone)
2309 validPrimitive = true;
2311 // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
2312 if (validUnit(value, FNumber | FLength | FNonNeg)) {
2313 RefPtr<CSSValue> val = createPrimitiveNumericValue(value);
2315 addProperty(propId, val.release(), important);
2322 case CSSPropertyWebkitPerspectiveOrigin:
2323 case CSSPropertyWebkitPerspectiveOriginX:
2324 case CSSPropertyWebkitPerspectiveOriginY: {
2325 RefPtr<CSSValue> val1;
2326 RefPtr<CSSValue> val2;
2327 CSSPropertyID propId1, propId2;
2328 if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
2329 addProperty(propId1, val1.release(), important);
2331 addProperty(propId2, val2.release(), important);
2336 case CSSPropertyAnimationDelay:
2337 case CSSPropertyAnimationDirection:
2338 case CSSPropertyAnimationDuration:
2339 case CSSPropertyAnimationFillMode:
2340 case CSSPropertyAnimationName:
2341 case CSSPropertyAnimationPlayState:
2342 case CSSPropertyAnimationIterationCount:
2343 case CSSPropertyAnimationTimingFunction:
2344 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
2346 case CSSPropertyWebkitAnimationDelay:
2347 case CSSPropertyWebkitAnimationDirection:
2348 case CSSPropertyWebkitAnimationDuration:
2349 case CSSPropertyWebkitAnimationFillMode:
2350 case CSSPropertyWebkitAnimationName:
2351 case CSSPropertyWebkitAnimationPlayState:
2352 case CSSPropertyWebkitAnimationIterationCount:
2353 case CSSPropertyWebkitAnimationTimingFunction:
2354 case CSSPropertyTransitionDelay:
2355 case CSSPropertyTransitionDuration:
2356 case CSSPropertyTransitionTimingFunction:
2357 case CSSPropertyTransitionProperty:
2358 case CSSPropertyWebkitTransitionDelay:
2359 case CSSPropertyWebkitTransitionDuration:
2360 case CSSPropertyWebkitTransitionTimingFunction:
2361 case CSSPropertyWebkitTransitionProperty: {
2362 RefPtr<CSSValue> val;
2363 AnimationParseContext context;
2364 if (parseAnimationProperty(propId, val, context)) {
2365 addPropertyWithPrefixingVariant(propId, val.release(), important);
2371 case CSSPropertyJustifySelf:
2372 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2375 return parseItemPositionOverflowPosition(propId, important);
2376 case CSSPropertyGridAutoColumns:
2377 case CSSPropertyGridAutoRows:
2378 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2380 parsedValue = parseGridTrackSize(*m_valueList);
2383 case CSSPropertyGridTemplateColumns:
2384 case CSSPropertyGridTemplateRows:
2385 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2387 return parseGridTrackList(propId, important);
2389 case CSSPropertyGridColumnEnd:
2390 case CSSPropertyGridColumnStart:
2391 case CSSPropertyGridRowEnd:
2392 case CSSPropertyGridRowStart:
2393 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2395 parsedValue = parseGridPosition();
2398 case CSSPropertyGridColumn:
2399 case CSSPropertyGridRow:
2400 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2402 return parseGridItemPositionShorthand(propId, important);
2404 case CSSPropertyGridArea:
2405 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2407 return parseGridAreaShorthand(important);
2409 case CSSPropertyGridTemplateAreas:
2410 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2412 parsedValue = parseGridTemplateAreas();
2415 case CSSPropertyWebkitMarginCollapse: {
2417 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2418 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important))
2420 CSSValue* value = m_parsedProperties.last().value();
2421 addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
2424 else if (num == 2) {
2425 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2426 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important) || !parseValue(webkitMarginCollapseShorthand().properties()[1], important))
2432 case CSSPropertyTextLineThroughWidth:
2433 case CSSPropertyTextOverlineWidth:
2434 case CSSPropertyTextUnderlineWidth:
2435 if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
2436 id == CSSValueMedium || id == CSSValueThick)
2437 validPrimitive = true;
2439 validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent);
2441 case CSSPropertyWebkitColumnCount:
2442 parsedValue = parseColumnCount();
2444 case CSSPropertyWebkitColumnGap: // normal | <length>
2445 if (id == CSSValueNormal)
2446 validPrimitive = true;
2448 validPrimitive = validUnit(value, FLength | FNonNeg);
2450 case CSSPropertyWebkitColumnAxis:
2451 if (id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
2452 validPrimitive = true;
2454 case CSSPropertyWebkitColumnProgression:
2455 if (id == CSSValueNormal || id == CSSValueReverse)
2456 validPrimitive = true;
2458 case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property)
2459 if (id == CSSValueAll || id == CSSValueNone)
2460 validPrimitive = true;
2462 validPrimitive = validUnit(value, FNumber | FNonNeg) && value->fValue == 1;
2464 case CSSPropertyWebkitColumnWidth: // auto | <length>
2465 parsedValue = parseColumnWidth();
2467 // End of CSS3 properties
2469 // Apple specific properties. These will never be standardized and are purely to
2470 // support custom WebKit-based Apple applications.
2471 case CSSPropertyWebkitLineClamp:
2472 // When specifying number of lines, don't allow 0 as a valid value
2473 // When specifying either type of unit, require non-negative integers
2474 validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, HTMLQuirksMode));
2477 case CSSPropertyWebkitFontSizeDelta: // <length>
2478 validPrimitive = validUnit(value, FLength);
2481 case CSSPropertyWebkitHighlight:
2482 if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
2483 validPrimitive = true;
2486 case CSSPropertyWebkitHyphenateCharacter:
2487 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2488 validPrimitive = true;
2491 case CSSPropertyWebkitLocale:
2492 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2493 validPrimitive = true;
2496 // End Apple-specific properties
2498 case CSSPropertyWebkitAppRegion:
2499 if (id >= CSSValueDrag && id <= CSSValueNoDrag)
2500 validPrimitive = true;
2503 case CSSPropertyWebkitTapHighlightColor:
2504 if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu
2505 || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
2506 validPrimitive = true;
2508 parsedValue = parseColor();
2510 m_valueList->next();
2514 /* shorthand properties */
2515 case CSSPropertyBackground: {
2516 // Position must come before color in this array because a plain old "0" is a legal color
2517 // in quirks mode but it's usually the X coordinate of a position.
2518 const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
2519 CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
2520 CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
2521 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
2523 case CSSPropertyWebkitMask: {
2524 const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
2525 CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize };
2526 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
2528 case CSSPropertyBorder:
2529 // [ 'border-width' || 'border-style' || <color> ] | inherit
2531 if (parseShorthand(propId, parsingShorthandForProperty(CSSPropertyBorder), important)) {
2532 // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as
2533 // though a value of none was specified for the image.
2534 addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
2539 case CSSPropertyBorderTop:
2540 // [ 'border-top-width' || 'border-style' || <color> ] | inherit
2541 return parseShorthand(propId, borderTopShorthand(), important);
2542 case CSSPropertyBorderRight:
2543 // [ 'border-right-width' || 'border-style' || <color> ] | inherit
2544 return parseShorthand(propId, borderRightShorthand(), important);
2545 case CSSPropertyBorderBottom:
2546 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
2547 return parseShorthand(propId, borderBottomShorthand(), important);
2548 case CSSPropertyBorderLeft:
2549 // [ 'border-left-width' || 'border-style' || <color> ] | inherit
2550 return parseShorthand(propId, borderLeftShorthand(), important);
2551 case CSSPropertyWebkitBorderStart:
2552 return parseShorthand(propId, webkitBorderStartShorthand(), important);
2553 case CSSPropertyWebkitBorderEnd:
2554 return parseShorthand(propId, webkitBorderEndShorthand(), important);
2555 case CSSPropertyWebkitBorderBefore:
2556 return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
2557 case CSSPropertyWebkitBorderAfter:
2558 return parseShorthand(propId, webkitBorderAfterShorthand(), important);
2559 case CSSPropertyOutline:
2560 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
2561 return parseShorthand(propId, outlineShorthand(), important);
2562 case CSSPropertyBorderColor:
2563 // <color>{1,4} | inherit
2564 return parse4Values(propId, borderColorShorthand().properties(), important);
2565 case CSSPropertyBorderWidth:
2566 // <border-width>{1,4} | inherit
2567 return parse4Values(propId, borderWidthShorthand().properties(), important);
2568 case CSSPropertyBorderStyle:
2569 // <border-style>{1,4} | inherit
2570 return parse4Values(propId, borderStyleShorthand().properties(), important);
2571 case CSSPropertyMargin:
2572 // <margin-width>{1,4} | inherit
2573 return parse4Values(propId, marginShorthand().properties(), important);
2574 case CSSPropertyPadding:
2575 // <padding-width>{1,4} | inherit
2576 return parse4Values(propId, paddingShorthand().properties(), important);
2577 case CSSPropertyFlexFlow:
2578 return parseShorthand(propId, flexFlowShorthand(), important);
2579 case CSSPropertyFont:
2580 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
2581 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
2582 if (id >= CSSValueCaption && id <= CSSValueStatusBar)
2583 validPrimitive = true;
2585 return parseFont(important);
2587 case CSSPropertyListStyle:
2588 return parseShorthand(propId, listStyleShorthand(), important);
2589 case CSSPropertyWebkitColumns:
2590 return parseColumnsShorthand(important);
2591 case CSSPropertyWebkitColumnRule:
2592 return parseShorthand(propId, webkitColumnRuleShorthand(), important);
2593 case CSSPropertyWebkitTextStroke:
2594 return parseShorthand(propId, webkitTextStrokeShorthand(), important);
2595 case CSSPropertyAnimation:
2596 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
2598 case CSSPropertyWebkitAnimation:
2599 return parseAnimationShorthand(propId, important);
2600 case CSSPropertyTransition:
2601 case CSSPropertyWebkitTransition:
2602 return parseTransitionShorthand(propId, important);
2603 case CSSPropertyInvalid:
2605 case CSSPropertyPage:
2606 return parsePage(propId, important);
2607 case CSSPropertyFontStretch:
2609 // CSS Text Layout Module Level 3: Vertical writing support
2610 case CSSPropertyWebkitTextEmphasis:
2611 return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
2613 case CSSPropertyWebkitTextEmphasisStyle:
2614 return parseTextEmphasisStyle(important);
2616 case CSSPropertyWebkitTextOrientation:
2617 // FIXME: For now just support sideways, sideways-right, upright and vertical-right.
2618 if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSValueVerticalRight || id == CSSValueUpright)
2619 validPrimitive = true;
2622 case CSSPropertyWebkitLineBoxContain:
2623 if (id == CSSValueNone)
2624 validPrimitive = true;
2626 return parseLineBoxContain(important);
2628 case CSSPropertyWebkitFontFeatureSettings:
2629 if (id == CSSValueNormal)
2630 validPrimitive = true;
2632 return parseFontFeatureSettings(important);
2635 case CSSPropertyFontVariantLigatures:
2636 if (id == CSSValueNormal)
2637 validPrimitive = true;
2639 return parseFontVariantLigatures(important);
2641 case CSSPropertyWebkitClipPath:
2642 if (id == CSSValueNone) {
2643 validPrimitive = true;
2644 } else if (value->unit == CSSParserValue::Function) {
2645 parsedValue = parseBasicShape();
2646 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
2647 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
2648 addProperty(propId, parsedValue.release(), important);
2652 case CSSPropertyShapeInside:
2653 case CSSPropertyShapeOutside:
2654 parsedValue = parseShapeProperty(propId);
2656 case CSSPropertyShapeMargin:
2657 case CSSPropertyShapePadding:
2658 validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FLength | FNonNeg));
2660 case CSSPropertyShapeImageThreshold:
2661 validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FNumber));
2664 case CSSPropertyTouchAction:
2665 // auto | none | [pan-x || pan-y]
2666 return parseTouchAction(important);
2668 case CSSPropertyAlignSelf:
2669 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
2670 return parseItemPositionOverflowPosition(propId, important);
2672 case CSSPropertyAlignItems:
2673 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
2674 return parseItemPositionOverflowPosition(propId, important);
2676 case CSSPropertyBorderBottomStyle:
2677 case CSSPropertyBorderCollapse:
2678 case CSSPropertyBorderLeftStyle:
2679 case CSSPropertyBorderRightStyle:
2680 case CSSPropertyBorderTopStyle:
2681 case CSSPropertyBoxSizing:
2682 case CSSPropertyCaptionSide:
2683 case CSSPropertyClear:
2684 case CSSPropertyDirection:
2685 case CSSPropertyDisplay:
2686 case CSSPropertyEmptyCells:
2687 case CSSPropertyFloat:
2688 case CSSPropertyFontStyle:
2689 case CSSPropertyImageRendering:
2690 case CSSPropertyListStylePosition:
2691 case CSSPropertyListStyleType:
2692 case CSSPropertyObjectFit:
2693 case CSSPropertyOutlineStyle:
2694 case CSSPropertyOverflowWrap:
2695 case CSSPropertyOverflowX:
2696 case CSSPropertyOverflowY:
2697 case CSSPropertyPageBreakAfter:
2698 case CSSPropertyPageBreakBefore:
2699 case CSSPropertyPageBreakInside:
2700 case CSSPropertyPointerEvents:
2701 case CSSPropertyPosition:
2702 case CSSPropertyResize:
2703 case CSSPropertySpeak:
2704 case CSSPropertyTableLayout:
2705 case CSSPropertyTextAlignLast:
2706 case CSSPropertyTextJustify:
2707 case CSSPropertyTextLineThroughMode:
2708 case CSSPropertyTextLineThroughStyle:
2709 case CSSPropertyTextOverflow:
2710 case CSSPropertyTextOverlineMode:
2711 case CSSPropertyTextOverlineStyle:
2712 case CSSPropertyTextRendering:
2713 case CSSPropertyTextTransform:
2714 case CSSPropertyTextUnderlineMode:
2715 case CSSPropertyTextUnderlineStyle:
2716 case CSSPropertyTouchActionDelay:
2717 case CSSPropertyVisibility:
2718 case CSSPropertyWebkitAppearance:
2719 case CSSPropertyWebkitBackfaceVisibility:
2720 case CSSPropertyWebkitBorderAfterStyle:
2721 case CSSPropertyWebkitBorderBeforeStyle:
2722 case CSSPropertyWebkitBorderEndStyle:
2723 case CSSPropertyWebkitBorderFit:
2724 case CSSPropertyWebkitBorderStartStyle:
2725 case CSSPropertyWebkitBoxAlign:
2726 case CSSPropertyWebkitBoxDecorationBreak:
2727 case CSSPropertyWebkitBoxDirection:
2728 case CSSPropertyWebkitBoxLines:
2729 case CSSPropertyWebkitBoxOrient:
2730 case CSSPropertyWebkitBoxPack:
2731 case CSSPropertyInternalCallback:
2732 case CSSPropertyWebkitColumnBreakAfter:
2733 case CSSPropertyWebkitColumnBreakBefore:
2734 case CSSPropertyWebkitColumnBreakInside:
2735 case CSSPropertyColumnFill:
2736 case CSSPropertyWebkitColumnRuleStyle:
2737 case CSSPropertyAlignContent:
2738 case CSSPropertyFlexDirection:
2739 case CSSPropertyFlexWrap:
2740 case CSSPropertyJustifyContent:
2741 case CSSPropertyFontKerning:
2742 case CSSPropertyWebkitFontSmoothing:
2743 case CSSPropertyGridAutoFlow:
2744 case CSSPropertyWebkitLineBreak:
2745 case CSSPropertyWebkitMarginAfterCollapse:
2746 case CSSPropertyWebkitMarginBeforeCollapse:
2747 case CSSPropertyWebkitMarginBottomCollapse:
2748 case CSSPropertyWebkitMarginTopCollapse:
2749 case CSSPropertyInternalMarqueeDirection:
2750 case CSSPropertyInternalMarqueeStyle:
2751 case CSSPropertyWebkitPrintColorAdjust:
2752 case CSSPropertyWebkitRtlOrdering:
2753 case CSSPropertyWebkitRubyPosition:
2754 case CSSPropertyWebkitTextCombine:
2755 case CSSPropertyWebkitTextEmphasisPosition:
2756 case CSSPropertyWebkitTextSecurity:
2757 case CSSPropertyWebkitTransformStyle:
2758 case CSSPropertyWebkitUserDrag:
2759 case CSSPropertyWebkitUserModify:
2760 case CSSPropertyWebkitUserSelect:
2761 case CSSPropertyWebkitWrapFlow:
2762 case CSSPropertyWebkitWrapThrough:
2763 case CSSPropertyWebkitWritingMode:
2764 case CSSPropertyWhiteSpace:
2765 case CSSPropertyWordBreak:
2766 case CSSPropertyWordWrap:
2767 case CSSPropertyMixBlendMode:
2768 case CSSPropertyIsolation:
2769 // These properties should be handled before in isValidKeywordPropertyAndValue().
2770 ASSERT_NOT_REACHED();
2772 // Properties below are validated inside parseViewportProperty, because we
2773 // check for parser state. We need to invalidate if someone adds them outside
2774 // a @viewport rule.
2775 case CSSPropertyMaxZoom:
2776 case CSSPropertyMinZoom:
2777 case CSSPropertyOrientation:
2778 case CSSPropertyUserZoom:
2779 validPrimitive = false;
2782 return parseSVGValue(propId, important);
2785 if (validPrimitive) {
2786 parsedValue = parseValidPrimitive(id, value);
2787 m_valueList->next();
2789 ASSERT(!m_parsedCalculation);
2791 if (!m_valueList->current() || inShorthand()) {
2792 addProperty(propId, parsedValue.release(), important);
2799 void BisonCSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
2802 if (lval->isBaseValueList())
2803 toCSSValueList(lval.get())->append(rval);
2805 PassRefPtr<CSSValue> oldlVal(lval.release());
2806 PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
2807 list->append(oldlVal);
2816 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue)
2818 if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
2819 || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
2820 cssValue = cssValuePool().createIdentifierValue(parserValue->id);
2826 bool BisonCSSParser::useLegacyBackgroundSizeShorthandBehavior() const
2828 return m_context.useLegacyBackgroundSizeShorthandBehavior();
2831 const int cMaxFillProperties = 9;
2833 bool BisonCSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
2835 ASSERT(numProperties <= cMaxFillProperties);
2836 if (numProperties > cMaxFillProperties)
2839 ShorthandScope scope(this, propId);
2841 bool parsedProperty[cMaxFillProperties] = { false };
2842 RefPtr<CSSValue> values[cMaxFillProperties];
2843 RefPtr<CSSValue> clipValue;
2844 RefPtr<CSSValue> positionYValue;
2845 RefPtr<CSSValue> repeatYValue;
2846 bool foundClip = false;
2848 bool foundPositionCSSProperty = false;
2850 while (m_valueList->current()) {
2851 CSSParserValue* val = m_valueList->current();
2852 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
2853 // We hit the end. Fill in all remaining values with the initial value.
2854 m_valueList->next();
2855 for (i = 0; i < numProperties; ++i) {
2856 if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
2857 // Color is not allowed except as the last item in a list for backgrounds.
2858 // Reject the entire property.
2861 if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
2862 addFillValue(values[i], cssValuePool().createImplicitInitialValue());
2863 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2864 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
2865 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2866 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
2867 if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
2868 // If background-origin wasn't present, then reset background-clip also.
2869 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
2872 parsedProperty[i] = false;
2874 if (!m_valueList->current())
2878 bool sizeCSSPropertyExpected = false;
2879 if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
2880 sizeCSSPropertyExpected = true;
2881 m_valueList->next();
2884 foundPositionCSSProperty = false;
2886 for (i = 0; !found && i < numProperties; ++i) {
2888 if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgroundSize && properties[i] != CSSPropertyWebkitMaskSize))
2890 if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgroundSize || properties[i] == CSSPropertyWebkitMaskSize))
2893 if (!parsedProperty[i]) {
2894 RefPtr<CSSValue> val1;
2895 RefPtr<CSSValue> val2;
2896 CSSPropertyID propId1, propId2;
2897 CSSParserValue* parserValue = m_valueList->current();
2898 // parseFillProperty() may modify m_implicitShorthand, so we MUST reset it
2899 // before EACH return below.
2900 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
2901 parsedProperty[i] = found = true;
2902 addFillValue(values[i], val1.release());
2903 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2904 addFillValue(positionYValue, val2.release());
2905 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2906 addFillValue(repeatYValue, val2.release());
2907 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
2908 // Reparse the value as a clip, and see if we succeed.
2909 if (parseBackgroundClip(parserValue, val1))
2910 addFillValue(clipValue, val1.release()); // The property parsed successfully.
2912 addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
2914 if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
2916 addFillValue(clipValue, val1.release());
2919 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2920 foundPositionCSSProperty = true;
2925 // if we didn't find at least one match, this is an
2926 // invalid shorthand and we have to ignore it
2928 m_implicitShorthand = false;
2933 // Now add all of the properties we found.
2934 for (i = 0; i < numProperties; i++) {
2935 // Fill in any remaining properties with the initial value.
2936 if (!parsedProperty[i]) {
2937 addFillValue(values[i], cssValuePool().createImplicitInitialValue());
2938 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2939 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
2940 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2941 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
2942 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
2943 // If background-origin wasn't present, then reset background-clip also.
2944 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
2947 if (properties[i] == CSSPropertyBackgroundPosition) {
2948 addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
2949 // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
2950 addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
2951 } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
2952 addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
2953 // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
2954 addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
2955 } else if (properties[i] == CSSPropertyBackgroundRepeat) {
2956 addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
2957 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
2958 addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
2959 } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
2960 addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
2961 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
2962 addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
2963 } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
2964 // Value is already set while updating origin
2966 else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i] && useLegacyBackgroundSizeShorthandBehavior())
2969 addProperty(properties[i], values[i].release(), important);
2971 // Add in clip values when we hit the corresponding origin property.
2972 if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
2973 addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
2974 else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
2975 addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
2978 m_implicitShorthand = false;
2982 void BisonCSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
2985 if (lval->isValueList())
2986 toCSSValueList(lval.get())->append(rval);
2988 PassRefPtr<CSSValue> oldVal(lval.release());
2989 PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
2990 list->append(oldVal);
2999 bool BisonCSSParser::parseAnimationShorthand(CSSPropertyID propId, bool important)
3001 const StylePropertyShorthand& animationProperties = parsingShorthandForProperty(propId);
3002 const unsigned numProperties = 8;
3004 // The list of properties in the shorthand should be the same
3005 // length as the list with animation name in last position, even though they are
3006 // in a different order.
3007 ASSERT(numProperties == animationProperties.length());
3008 ASSERT(numProperties == shorthandForProperty(propId).length());
3010 ShorthandScope scope(this, propId);
3012 bool parsedProperty[numProperties] = { false };
3013 AnimationParseContext context;
3014 RefPtr<CSSValue> values[numProperties];
3017 while (m_valueList->current()) {
3018 CSSParserValue* val = m_valueList->current();
3019 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3020 // We hit the end. Fill in all remaining values with the initial value.
3021 m_valueList->next();
3022 for (i = 0; i < numProperties; ++i) {
3023 if (!parsedProperty[i])
3024 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3025 parsedProperty[i] = false;
3027 if (!m_valueList->current())
3029 context.commitFirstAnimation();
3033 for (i = 0; i < numProperties; ++i) {
3034 if (!parsedProperty[i]) {
3035 RefPtr<CSSValue> val;
3036 if (parseAnimationProperty(animationProperties.properties()[i], val, context)) {
3037 parsedProperty[i] = found = true;
3038 addAnimationValue(values[i], val.release());
3044 // if we didn't find at least one match, this is an
3045 // invalid shorthand and we have to ignore it
3050 for (i = 0; i < numProperties; ++i) {
3051 // If we didn't find the property, set an intial value.
3052 if (!parsedProperty[i])
3053 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3055 addProperty(animationProperties.properties()[i], values[i].release(), important);
3061 bool BisonCSSParser::parseTransitionShorthand(CSSPropertyID propId, bool important)
3063 const unsigned numProperties = 4;
3064 const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
3065 ASSERT(numProperties == shorthand.length());
3067 ShorthandScope scope(this, propId);
3069 bool parsedProperty[numProperties] = { false };
3070 AnimationParseContext context;
3071 RefPtr<CSSValue> values[numProperties];
3074 while (m_valueList->current()) {
3075 CSSParserValue* val = m_valueList->current();
3076 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3077 // We hit the end. Fill in all remaining values with the initial value.
3078 m_valueList->next();
3079 for (i = 0; i < numProperties; ++i) {
3080 if (!parsedProperty[i])
3081 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3082 parsedProperty[i] = false;
3084 if (!m_valueList->current())
3086 context.commitFirstAnimation();
3090 for (i = 0; !found && i < numProperties; ++i) {
3091 if (!parsedProperty[i]) {
3092 RefPtr<CSSValue> val;
3093 if (parseAnimationProperty(shorthand.properties()[i], val, context)) {
3094 parsedProperty[i] = found = true;
3095 addAnimationValue(values[i], val.release());
3098 // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid.
3099 if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation())
3104 // if we didn't find at least one match, this is an
3105 // invalid shorthand and we have to ignore it
3110 // Fill in any remaining properties with the initial value.
3111 for (i = 0; i < numProperties; ++i) {
3112 if (!parsedProperty[i])
3113 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3116 // Now add all of the properties we found.
3117 for (i = 0; i < numProperties; i++)
3118 addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].release(), important);
3123 PassRefPtr<CSSValue> BisonCSSParser::parseColumnWidth()
3125 CSSParserValue* value = m_valueList->current();
3126 // Always parse lengths in strict mode here, since it would be ambiguous otherwise when used in
3127 // the 'columns' shorthand property.
3128 if (value->id == CSSValueAuto
3129 || (validUnit(value, FLength | FNonNeg, HTMLStandardMode) && value->fValue)) {
3130 RefPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
3131 m_valueList->next();
3137 PassRefPtr<CSSValue> BisonCSSParser::parseColumnCount()
3139 CSSParserValue* value = m_valueList->current();
3140 if (value->id == CSSValueAuto
3141 || (!value->id && validUnit(value, FPositiveInteger, HTMLQuirksMode))) {
3142 RefPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
3143 m_valueList->next();
3149 bool BisonCSSParser::parseColumnsShorthand(bool important)
3151 RefPtr <CSSValue> columnWidth;
3152 RefPtr <CSSValue> columnCount;
3153 bool hasPendingExplicitAuto = false;
3155 for (unsigned propertiesParsed = 0; CSSParserValue* value = m_valueList->current(); propertiesParsed++) {
3156 if (propertiesParsed >= 2)
3157 return false; // Too many values for this shorthand. Invalid declaration.
3158 if (!propertiesParsed && value->id == CSSValueAuto) {
3159 // 'auto' is a valid value for any of the two longhands, and at this point we
3160 // don't know which one(s) it is meant for. We need to see if there are other
3162 m_valueList->next();
3163 hasPendingExplicitAuto = true;
3166 if ((columnWidth = parseColumnWidth()))
3170 if ((columnCount = parseColumnCount()))
3173 // If we didn't find at least one match, this is an
3174 // invalid shorthand and we have to ignore it.
3178 if (hasPendingExplicitAuto) {
3179 // Time to assign the previously skipped 'auto' value to a property. If both properties are
3180 // unassigned at this point (i.e. 'columns:auto'), it doesn't matter that much which one we
3181 // set (although it does make a slight difference to web-inspector). The one we don't set
3182 // here will get an implicit 'auto' value further down.
3184 columnWidth = cssValuePool().createIdentifierValue(CSSValueAuto);
3186 ASSERT(!columnCount);
3187 columnCount = cssValuePool().createIdentifierValue(CSSValueAuto);
3190 ASSERT(columnCount || columnWidth);
3192 // Any unassigned property at this point will become implicit 'auto'.
3194 addProperty(CSSPropertyWebkitColumnWidth, columnWidth, important);
3196 addProperty(CSSPropertyWebkitColumnWidth, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
3198 addProperty(CSSPropertyWebkitColumnCount, columnCount, important);
3200 addProperty(CSSPropertyWebkitColumnCount, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
3204 bool BisonCSSParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
3206 // We try to match as many properties as possible
3207 // We set up an array of booleans to mark which property has been found,
3208 // and we try to search for properties until it makes no longer any sense.
3209 ShorthandScope scope(this, propId);
3212 unsigned propertiesParsed = 0;
3213 bool propertyFound[6] = { false, false, false, false, false, false }; // 6 is enough size.
3215 while (m_valueList->current()) {
3217 for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
3218 if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
3219 propertyFound[propIndex] = found = true;
3224 // if we didn't find at least one match, this is an
3225 // invalid shorthand and we have to ignore it
3230 if (propertiesParsed == shorthand.length())
3233 // Fill in any remaining properties with the initial value.
3234 ImplicitScope implicitScope(this, PropertyImplicit);
3235 const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization();
3236 for (unsigned i = 0; i < shorthand.length(); ++i) {
3237 if (propertyFound[i])
3240 if (propertiesForInitialization) {
3241 const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]);
3242 for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
3243 addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
3245 addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
3251 bool BisonCSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties, bool important)
3253 /* From the CSS 2 specs, 8.3
3254 * If there is only one value, it applies to all sides. If there are two values, the top and
3255 * bottom margins are set to the first value and the right and left margins are set to the second.
3256 * If there are three values, the top is set to the first value, the left and right are set to the
3257 * second, and the bottom is set to the third. If there are four values, they apply to the top,
3258 * right, bottom, and left, respectively.
3261 int num = inShorthand() ? 1 : m_valueList->size();
3263 ShorthandScope scope(this, propId);
3265 // the order is top, right, bottom, left
3268 if (!parseValue(properties[0], important))
3270 CSSValue* value = m_parsedProperties.last().value();
3271 ImplicitScope implicitScope(this, PropertyImplicit);
3272 addProperty(properties[1], value, important);
3273 addProperty(properties[2], value, important);
3274 addProperty(properties[3], value, important);
3278 if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
3280 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3281 ImplicitScope implicitScope(this, PropertyImplicit);
3282 addProperty(properties[2], value, important);
3283 value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3284 addProperty(properties[3], value, important);
3288 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
3290 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3291 ImplicitScope implicitScope(this, PropertyImplicit);
3292 addProperty(properties[3], value, important);
3296 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
3297 !parseValue(properties[2], important) || !parseValue(properties[3], important))
3309 // auto | <identifier>
3310 bool BisonCSSParser::parsePage(CSSPropertyID propId, bool important)
3312 ASSERT(propId == CSSPropertyPage);
3314 if (m_valueList->size() != 1)
3317 CSSParserValue* value = m_valueList->current();
3321 if (value->id == CSSValueAuto) {
3322 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
3324 } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
3325 addProperty(propId, createPrimitiveStringValue(value), important);
3331 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
3332 bool BisonCSSParser::parseSize(CSSPropertyID propId, bool important)
3334 ASSERT(propId == CSSPropertySize);
3336 if (m_valueList->size() > 2)
3339 CSSParserValue* value = m_valueList->current();
3343 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
3346 SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
3347 if (paramType == None)
3350 // Second parameter, if any.
3351 value = m_valueList->next();
3353 paramType = parseSizeParameter(parsedValues.get(), value, paramType);
3354 if (paramType == None)
3358 addProperty(propId, parsedValues.release(), important);
3362 BisonCSSParser::SizeParameterType BisonCSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
3364 switch (value->id) {
3366 if (prevParamType == None) {
3367 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3371 case CSSValueLandscape:
3372 case CSSValuePortrait:
3373 if (prevParamType == None || prevParamType == PageSize) {
3374 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3383 case CSSValueLedger:
3385 case CSSValueLetter:
3386 if (prevParamType == None || prevParamType == Orientation) {
3387 // Normalize to Page Size then Orientation order by prepending.
3388 // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
3389 parsedValues->prepend(cssValuePool().createIdentifierValue(value->id));
3394 if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) {
3395 parsedValues->append(createPrimitiveNumericValue(value));
3404 // [ <string> <string> ]+ | inherit | none
3405 // inherit and none are handled in parseValue.
3406 bool BisonCSSParser::parseQuotes(CSSPropertyID propId, bool important)
3408 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3409 while (CSSParserValue* val = m_valueList->current()) {
3410 RefPtr<CSSValue> parsedValue;
3411 if (val->unit == CSSPrimitiveValue::CSS_STRING)
3412 parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
3415 values->append(parsedValue.release());
3416 m_valueList->next();
3418 if (values->length()) {
3419 addProperty(propId, values.release(), important);
3420 m_valueList->next();
3426 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
3427 // in CSS 2.1 this got somewhat reduced:
3428 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
3429 bool BisonCSSParser::parseContent(CSSPropertyID propId, bool important)
3431 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3433 while (CSSParserValue* val = m_valueList->current()) {
3434 RefPtr<CSSValue> parsedValue;
3435 if (val->unit == CSSPrimitiveValue::CSS_URI) {
3437 parsedValue = CSSImageValue::create(completeURL(val->string));
3438 } else if (val->unit == CSSParserValue::Function) {
3439 // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
3440 CSSParserValueList* args = val->function->args.get();
3443 if (equalIgnoringCase(val->function->name, "attr(")) {
3444 parsedValue = parseAttr(args);
3447 } else if (equalIgnoringCase(val->function->name, "counter(")) {
3448 parsedValue = parseCounterContent(args, false);
3451 } else if (equalIgnoringCase(val->function->name, "counters(")) {
3452 parsedValue = parseCounterContent(args, true);
3455 } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
3456 parsedValue = parseImageSet(m_valueList.get());
3459 } else if (isGeneratedImageValue(val)) {
3460 if (!parseGeneratedImage(m_valueList.get(), parsedValue))
3464 } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
3470 // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
3474 case CSSValueOpenQuote:
3475 case CSSValueCloseQuote:
3476 case CSSValueNoOpenQuote:
3477 case CSSValueNoCloseQuote:
3479 case CSSValueNormal:
3480 parsedValue = cssValuePool().createIdentifierValue(val->id);
3484 } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
3485 parsedValue = createPrimitiveStringValue(val);
3489 values->append(parsedValue.release());
3490 m_valueList->next();
3493 if (values->length()) {
3494 addProperty(propId, values.release(), important);
3495 m_valueList->next();
3502 PassRefPtr<CSSValue> BisonCSSParser::parseAttr(CSSParserValueList* args)
3504 if (args->size() != 1)
3507 CSSParserValue* a = args->current();
3509 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
3512 String attrName = a->string;
3513 // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
3514 // But HTML attribute names can't have those characters, and we should not
3515 // even parse them inside attr().
3516 if (attrName[0] == '-')
3519 if (m_context.isHTMLDocument())
3520 attrName = attrName.lower();
3522 return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
3525 PassRefPtr<CSSValue> BisonCSSParser::parseBackgroundColor()
3527 CSSValueID id = m_valueList->current()->id;
3528 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
3529 (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
3530 return cssValuePool().createIdentifierValue(id);
3531 return parseColor();
3534 bool BisonCSSParser::parseFillImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
3536 if (valueList->current()->id == CSSValueNone) {
3537 value = cssValuePool().createIdentifierValue(CSSValueNone);
3540 if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
3541 value = CSSImageValue::create(completeURL(valueList->current()->string));
3545 if (isGeneratedImageValue(valueList->current()))
3546 return parseGeneratedImage(valueList, value);
3548 if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) {
3549 value = parseImageSet(m_valueList.get());
3557 PassRefPtr<CSSValue> BisonCSSParser::parseFillPositionX(CSSParserValueList* valueList)
3559 int id = valueList->current()->id;
3560 if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
3562 if (id == CSSValueRight)
3564 else if (id == CSSValueCenter)
3566 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3568 if (validUnit(valueList->current(), FPercent | FLength))
3569 return createPrimitiveNumericValue(valueList->current());
3573 PassRefPtr<CSSValue> BisonCSSParser::parseFillPositionY(CSSParserValueList* valueList)
3575 int id = valueList->current()->id;
3576 if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
3578 if (id == CSSValueBottom)
3580 else if (id == CSSValueCenter)
3582 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3584 if (validUnit(valueList->current(), FPercent | FLength))
3585 return createPrimitiveNumericValue(valueList->current());
3589 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> BisonCSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode)
3591 CSSValueID id = valueList->current()->id;
3592 if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
3594 if (id == CSSValueLeft || id == CSSValueRight) {
3595 if (cumulativeFlags & XFillPosition)
3597 cumulativeFlags |= XFillPosition;
3598 individualFlag = XFillPosition;
3599 if (id == CSSValueRight)
3602 else if (id == CSSValueTop || id == CSSValueBottom) {
3603 if (cumulativeFlags & YFillPosition)
3605 cumulativeFlags |= YFillPosition;
3606 individualFlag = YFillPosition;
3607 if (id == CSSValueBottom)
3609 } else if (id == CSSValueCenter) {
3610 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
3612 cumulativeFlags |= AmbiguousFillPosition;
3613 individualFlag = AmbiguousFillPosition;
3616 if (parsingMode == ResolveValuesAsKeyword)
3617 return cssValuePool().createIdentifierValue(id);
3619 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3621 if (validUnit(valueList->current(), FPercent | FLength)) {
3622 if (!cumulativeFlags) {
3623 cumulativeFlags |= XFillPosition;
3624 individualFlag = XFillPosition;
3625 } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
3626 cumulativeFlags |= YFillPosition;
3627 individualFlag = YFillPosition;
3629 if (m_parsedCalculation)
3630 m_parsedCalculation.release();
3633 return createPrimitiveNumericValue(valueList->current());
3638 static bool isValueConflictingWithCurrentEdge(int value1, int value2)
3640 if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSValueLeft || value2 == CSSValueRight))
3643 if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSValueTop || value2 == CSSValueBottom))
3649 static bool isFillPositionKeyword(CSSValueID value)
3651 return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter;
3654 void BisonCSSParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2)
3656 // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <percentage> | <length> ]
3657 // In the case of 4 values <position> requires the second value to be a length or a percentage.
3658 if (isFillPositionKeyword(parsedValue2->getValueID()))
3661 unsigned cumulativeFlags = 0;
3662 FillPositionFlag value3Flag = InvalidFillPosition;
3663 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
3667 CSSValueID ident1 = parsedValue1->getValueID();
3668 CSSValueID ident3 = value3->getValueID();
3670 if (ident1 == CSSValueCenter)
3673 if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
3676 // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
3677 // needed as the second call to parseFillPositionComponent was on purpose not checking it. In the
3678 // case of two values top 20px is invalid but in the case of 4 values it becomes valid.
3679 if (isValueConflictingWithCurrentEdge(ident1, ident3))
3684 cumulativeFlags = 0;
3685 FillPositionFlag value4Flag = InvalidFillPosition;
3686 RefPtrWillBeRawPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(valueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
3690 // 4th value must be a length or a percentage.
3691 if (isFillPositionKeyword(value4->getValueID()))
3694 value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
3695 value2 = createPrimitiveValuePair(value3, value4);
3697 if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
3698 value1.swap(value2);
3702 void BisonCSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2)
3704 unsigned cumulativeFlags = 0;
3705 FillPositionFlag value3Flag = InvalidFillPosition;
3706 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
3708 // value3 is not an expected value, we return.
3714 bool swapNeeded = false;
3715 CSSValueID ident1 = parsedValue1->getValueID();
3716 CSSValueID ident2 = parsedValue2->getValueID();
3717 CSSValueID ident3 = value3->getValueID();
3719 CSSValueID firstPositionKeyword;
3720 CSSValueID secondPositionKeyword;
3722 if (ident1 == CSSValueCenter) {
3723 // <position> requires the first 'center' to be followed by a keyword.
3724 if (!isFillPositionKeyword(ident2))
3727 // If 'center' is the first keyword then the last one needs to be a length.
3728 if (isFillPositionKeyword(ident3))
3731 firstPositionKeyword = CSSValueLeft;
3732 if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
3733 firstPositionKeyword = CSSValueTop;
3736 value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
3737 value2 = createPrimitiveValuePair(parsedValue2, value3);
3738 } else if (ident3 == CSSValueCenter) {
3739 if (isFillPositionKeyword(ident2))
3742 secondPositionKeyword = CSSValueTop;
3743 if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
3744 secondPositionKeyword = CSSValueLeft;
3747 value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
3748 value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
3750 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstPositionValue;
3751 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondPositionValue;
3753 if (isFillPositionKeyword(ident2)) {
3754 // To match CSS grammar, we should only accept: [ center | left | right | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ].
3755 ASSERT(ident2 != CSSValueCenter);
3757 if (isFillPositionKeyword(ident3))
3760 secondPositionValue = value3;
3761 secondPositionKeyword = ident2;
3762 firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
3764 // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
3765 if (!isFillPositionKeyword(ident3))
3768 firstPositionValue = parsedValue2;
3769 secondPositionKeyword = ident3;
3770 secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
3773 if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
3776 value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue);
3777 value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue);
3780 if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
3781 value1.swap(value2);
3784 CSSPrimitiveValue* first = toCSSPrimitiveValue(value1.get());
3785 CSSPrimitiveValue* second = toCSSPrimitiveValue(value2.get());
3786 ident1 = first->getPairValue()->first()->getValueID();
3787 ident2 = second->getPairValue()->first()->getValueID();
3788 ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
3789 ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
3793 inline bool BisonCSSParser::isPotentialPositionValue(CSSParserValue* value)
3795 return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue);
3798 void BisonCSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
3800 unsigned numberOfValues = 0;
3801 for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++numberOfValues) {
3802 CSSParserValue* current = valueList->valueAt(i);
3803 if (isComma(current) || !current || isForwardSlashOperator(current) || !isPotentialPositionValue(current))
3807 if (numberOfValues > 4)
3810 // If we are parsing two values, we can safely call the CSS 2.1 parsing function and return.
3811 if (numberOfValues <= 2) {
3812 parse2ValuesFillPosition(valueList, value1, value2);
3816 ASSERT(numberOfValues > 2 && numberOfValues <= 4);
3818 CSSParserValue* value = valueList->current();
3820 // <position> requires the first value to be a background keyword.
3821 if (!isFillPositionKeyword(value->id))
3824 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
3825 unsigned cumulativeFlags = 0;
3826 FillPositionFlag value1Flag = InvalidFillPosition;
3827 FillPositionFlag value2Flag = InvalidFillPosition;
3828 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
3834 // In case we are parsing more than two values, relax the check inside of parseFillPositionComponent. top 20px is
3835 // a valid start for <position>.
3836 cumulativeFlags = AmbiguousFillPosition;
3837 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
3845 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(value1.get());
3846 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(value2.get());
3851 // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
3852 if (parsedValue2->getValueID() == CSSValueCenter)
3855 if (numberOfValues == 3)
3856 parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
3858 parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
3861 void BisonCSSParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
3863 CSSParserValue* value = valueList->current();
3865 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
3866 unsigned cumulativeFlags = 0;
3867 FillPositionFlag value1Flag = InvalidFillPosition;
3868 FillPositionFlag value2Flag = InvalidFillPosition;
3869 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
3873 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
3874 // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the
3875 // value was explicitly specified for our property.
3876 value = valueList->next();
3878 // First check for the comma. If so, we are finished parsing this value or value pair.
3883 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
3887 if (!inShorthand()) {
3895 // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
3896 // is simply 50%. This is our default.
3897 // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
3898 // For left/right/center, the default of 50% in the y is still correct.
3899 value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
3901 if (value1Flag == YFillPosition || value2Flag == XFillPosition)
3902 value1.swap(value2);
3905 void BisonCSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
3907 CSSValueID id = m_valueList->current()->id;
3908 if (id == CSSValueRepeatX) {
3909 m_implicitShorthand = true;
3910 value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
3911 value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
3912 m_valueList->next();
3915 if (id == CSSValueRepeatY) {
3916 m_implicitShorthand = true;
3917 value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
3918 value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
3919 m_valueList->next();
3922 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
3923 value1 = cssValuePool().createIdentifierValue(id);
3929 CSSParserValue* value = m_valueList->next();
3931 // Parse the second value if one is available
3932 if (value && !isComma(value)) {
3934 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
3935 value2 = cssValuePool().createIdentifierValue(id);
3936 m_valueList->next();
3941 // If only one value was specified, value2 is the same as value1.
3942 m_implicitShorthand = true;
3943 value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get())->getValueID());
3946 PassRefPtr<CSSValue> BisonCSSParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
3949 CSSParserValue* value = m_valueList->current();
3951 if (value->id == CSSValueContain || value->id == CSSValueCover)
3952 return cssValuePool().createIdentifierValue(value->id);
3954 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1;
3956 if (value->id == CSSValueAuto)
3957 parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
3959 if (!validUnit(value, FLength | FPercent))
3961 parsedValue1 = createPrimitiveNumericValue(value);
3964 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2;
3965 if ((value = m_valueList->next())) {
3966 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
3968 else if (value->id != CSSValueAuto) {
3969 if (!validUnit(value, FLength | FPercent)) {
3972 // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
3973 m_valueList->previous();
3975 parsedValue2 = createPrimitiveNumericValue(value);
3977 } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
3978 // For backwards compatibility we set the second value to the first if it is omitted.
3979 // We only need to do this for -webkit-background-size. It should be safe to let masks match
3980 // the real property.
3981 parsedValue2 = parsedValue1;
3985 return parsedValue1;
3986 return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release());
3989 bool BisonCSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
3990 RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
3992 RefPtrWillBeRawPtr<CSSValueList> values;
3993 RefPtrWillBeRawPtr<CSSValueList> values2;
3994 CSSParserValue* val;
3995 RefPtr<CSSValue> value;
3996 RefPtr<CSSValue> value2;
3998 bool allowComma = false;
4000 retValue1 = retValue2 = 0;
4003 if (propId == CSSPropertyBackgroundPosition) {
4004 propId1 = CSSPropertyBackgroundPositionX;
4005 propId2 = CSSPropertyBackgroundPositionY;
4006 } else if (propId == CSSPropertyWebkitMaskPosition) {
4007 propId1 = CSSPropertyWebkitMaskPositionX;
4008 propId2 = CSSPropertyWebkitMaskPositionY;
4009 } else if (propId == CSSPropertyBackgroundRepeat) {
4010 propId1 = CSSPropertyBackgroundRepeatX;
4011 propId2 = CSSPropertyBackgroundRepeatY;
4012 } else if (propId == CSSPropertyWebkitMaskRepeat) {
4013 propId1 = CSSPropertyWebkitMaskRepeatX;
4014 propId2 = CSSPropertyWebkitMaskRepeatY;
4017 while ((val = m_valueList->current())) {
4018 RefPtr<CSSValue> currValue;
4019 RefPtr<CSSValue> currValue2;
4024 m_valueList->next();
4029 case CSSPropertyBackgroundColor:
4030 currValue = parseBackgroundColor();
4032 m_valueList->next();
4034 case CSSPropertyBackgroundAttachment:
4035 if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
4036 currValue = cssValuePool().createIdentifierValue(val->id);
4037 m_valueList->next();
4040 case CSSPropertyBackgroundImage:
4041 case CSSPropertyWebkitMaskImage:
4042 if (parseFillImage(m_valueList.get(), currValue))
4043 m_valueList->next();
4045 case CSSPropertyWebkitBackgroundClip:
4046 case CSSPropertyWebkitBackgroundOrigin:
4047 case CSSPropertyWebkitMaskClip:
4048 case CSSPropertyWebkitMaskOrigin:
4049 // The first three values here are deprecated and do not apply to the version of the property that has
4050 // the -webkit- prefix removed.
4051 if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
4052 val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
4053 ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
4054 (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
4055 currValue = cssValuePool().createIdentifierValue(val->id);
4056 m_valueList->next();
4059 case CSSPropertyBackgroundClip:
4060 if (parseBackgroundClip(val, currValue))
4061 m_valueList->next();
4063 case CSSPropertyBackgroundOrigin:
4064 if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
4065 currValue = cssValuePool().createIdentifierValue(val->id);
4066 m_valueList->next();
4069 case CSSPropertyBackgroundPosition:
4070 case CSSPropertyWebkitMaskPosition:
4071 parseFillPosition(m_valueList.get(), currValue, currValue2);
4072 // parseFillPosition advances the m_valueList pointer.
4074 case CSSPropertyBackgroundPositionX:
4075 case CSSPropertyWebkitMaskPositionX: {
4076 currValue = parseFillPositionX(m_valueList.get());
4078 m_valueList->next();
4081 case CSSPropertyBackgroundPositionY:
4082 case CSSPropertyWebkitMaskPositionY: {
4083 currValue = parseFillPositionY(m_valueList.get());
4085 m_valueList->next();
4088 case CSSPropertyWebkitBackgroundComposite:
4089 case CSSPropertyWebkitMaskComposite:
4090 if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) {
4091 currValue = cssValuePool().createIdentifierValue(val->id);
4092 m_valueList->next();
4095 case CSSPropertyBackgroundBlendMode:
4096 if (RuntimeEnabledFeatures::cssCompositingEnabled() && (val->id == CSSValueNormal || val->id == CSSValueMultiply
4097 || val->id == CSSValueScreen || val->id == CSSValueOverlay || val->id == CSSValueDarken
4098 || val->id == CSSValueLighten || val->id == CSSValueColorDodge || val->id == CSSValueColorBurn
4099 || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference
4100 || val->id == CSSValueExclusion || val->id == CSSValueHue || val->id == CSSValueSaturation
4101 || val->id == CSSValueColor || val->id == CSSValueLuminosity)) {
4102 currValue = cssValuePool().createIdentifierValue(val->id);
4103 m_valueList->next();
4106 case CSSPropertyBackgroundRepeat:
4107 case CSSPropertyWebkitMaskRepeat:
4108 parseFillRepeat(currValue, currValue2);
4109 // parseFillRepeat advances the m_valueList pointer
4111 case CSSPropertyBackgroundSize:
4112 case CSSPropertyWebkitBackgroundSize:
4113 case CSSPropertyWebkitMaskSize: {
4114 currValue = parseFillSize(propId, allowComma);
4116 m_valueList->next();
4119 case CSSPropertyMaskSourceType: {
4120 if (RuntimeEnabledFeatures::cssMaskSourceTypeEnabled()) {
4121 if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id == CSSValueLuminance) {
4122 currValue = cssValuePool().createIdentifierValue(val->id);
4123 m_valueList->next();
4136 if (value && !values) {
4137 values = CSSValueList::createCommaSeparated();
4138 values->append(value.release());
4141 if (value2 && !values2) {
4142 values2 = CSSValueList::createCommaSeparated();
4143 values2->append(value2.release());
4147 values->append(currValue.release());
4149 value = currValue.release();
4152 values2->append(currValue2.release());
4154 value2 = currValue2.release();
4158 // When parsing any fill shorthand property, we let it handle building up the lists for all
4164 if (values && values->length()) {
4165 retValue1 = values.release();
4166 if (values2 && values2->length())
4167 retValue2 = values2.release();
4171 retValue1 = value.release();
4172 retValue2 = value2.release();
4178 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationDelay()
4180 CSSParserValue* value = m_valueList->current();
4181 if (validUnit(value, FTime))
4182 return createPrimitiveNumericValue(value);
4186 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationDirection()
4188 CSSParserValue* value = m_valueList->current();
4189 if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
4190 return cssValuePool().createIdentifierValue(value->id);
4194 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationDuration()
4196 CSSParserValue* value = m_valueList->current();
4197 if (validUnit(value, FTime | FNonNeg))
4198 return createPrimitiveNumericValue(value);
4202 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationFillMode()
4204 CSSParserValue* value = m_valueList->current();
4205 if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
4206 return cssValuePool().createIdentifierValue(value->id);
4210 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationIterationCount()
4212 CSSParserValue* value = m_valueList->current();
4213 if (value->id == CSSValueInfinite)
4214 return cssValuePool().createIdentifierValue(value->id);
4215 if (validUnit(value, FNumber | FNonNeg))
4216 return createPrimitiveNumericValue(value);
4220 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationName()
4222 CSSParserValue* value = m_valueList->current();
4223 if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
4224 if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value, "none"))) {
4225 return cssValuePool().createIdentifierValue(CSSValueNone);
4227 return createPrimitiveStringValue(value);
4233 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationPlayState()
4235 CSSParserValue* value = m_valueList->current();
4236 if (value->id == CSSValueRunning || value->id == CSSValuePaused)
4237 return cssValuePool().createIdentifierValue(value->id);
4241 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationProperty(AnimationParseContext& context)
4243 CSSParserValue* value = m_valueList->current();
4244 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
4246 CSSPropertyID result = cssPropertyID(value->string);
4248 return cssValuePool().createIdentifierValue(result);
4249 if (equalIgnoringCase(value, "all")) {
4250 context.sawAnimationPropertyKeyword();
4251 return cssValuePool().createIdentifierValue(CSSValueAll);
4253 if (equalIgnoringCase(value, "none")) {
4254 context.commitAnimationPropertyKeyword();
4255 context.sawAnimationPropertyKeyword();
4256 return cssValuePool().createIdentifierValue(CSSValueNone);
4261 bool BisonCSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
4263 parse2ValuesFillPosition(m_valueList.get(), value1, value2);
4266 if (m_valueList->current()) {
4267 if (validUnit(m_valueList->current(), FLength)) {
4268 value3 = createPrimitiveNumericValue(m_valueList->current());
4269 m_valueList->next();
4274 value3 = cssValuePool().createImplicitInitialValue();
4278 bool BisonCSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
4280 CSSParserValue* v = args->current();
4281 if (!validUnit(v, FNumber))
4286 // The last number in the function has no comma after it, so we're done.
4294 PassRefPtr<CSSValue> BisonCSSParser::parseAnimationTimingFunction()
4296 CSSParserValue* value = m_valueList->current();
4297 if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
4298 || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd)
4299 return cssValuePool().createIdentifierValue(value->id);
4301 // We must be a function.
4302 if (value->unit != CSSParserValue::Function)
4305 CSSParserValueList* args = value->function->args.get();
4307 if (equalIgnoringCase(value->function->name, "steps(")) {
4308 // For steps, 1 or 2 params must be specified (comma-separated)
4309 if (!args || (args->size() != 1 && args->size() != 3))
4312 // There are two values.
4314 bool stepAtStart = false;
4316 CSSParserValue* v = args->current();
4317 if (!validUnit(v, FInteger))
4319 numSteps = clampToInteger(v->fValue);
4325 // There is a comma so we need to parse the second value
4329 if (v->id != CSSValueStart && v->id != CSSValueEnd)
4331 stepAtStart = v->id == CSSValueStart;
4334 return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart);
4337 if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
4338 // For cubic bezier, 4 values must be specified.
4339 if (!args || args->size() != 7)
4342 // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range.
4343 double x1, y1, x2, y2;
4345 if (!parseCubicBezierTimingFunctionValue(args, x1))
4347 if (x1 < 0 || x1 > 1)
4349 if (!parseCubicBezierTimingFunctionValue(args, y1))
4351 if (!parseCubicBezierTimingFunctionValue(args, x2))
4353 if (x2 < 0 || x2 > 1)
4355 if (!parseCubicBezierTimingFunctionValue(args, y2))
4358 return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
4364 bool BisonCSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& result, AnimationParseContext& context)
4366 RefPtrWillBeRawPtr<CSSValueList> values;
4367 CSSParserValue* val;
4368 RefPtr<CSSValue> value;
4369 bool allowComma = false;
4373 while ((val = m_valueList->current())) {
4374 RefPtr<CSSValue> currValue;
4378 m_valueList->next();
4383 case CSSPropertyAnimationDelay:
4384 case CSSPropertyWebkitAnimationDelay:
4385 case CSSPropertyTransitionDelay:
4386 case CSSPropertyWebkitTransitionDelay:
4387 currValue = parseAnimationDelay();
4389 m_valueList->next();
4391 case CSSPropertyAnimationDirection:
4392 case CSSPropertyWebkitAnimationDirection:
4393 currValue = parseAnimationDirection();
4395 m_valueList->next();
4397 case CSSPropertyAnimationDuration:
4398 case CSSPropertyWebkitAnimationDuration:
4399 case CSSPropertyTransitionDuration:
4400 case CSSPropertyWebkitTransitionDuration:
4401 currValue = parseAnimationDuration();
4403 m_valueList->next();
4405 case CSSPropertyAnimationFillMode:
4406 case CSSPropertyWebkitAnimationFillMode:
4407 currValue = parseAnimationFillMode();
4409 m_valueList->next();
4411 case CSSPropertyAnimationIterationCount:
4412 case CSSPropertyWebkitAnimationIterationCount:
4413 currValue = parseAnimationIterationCount();
4415 m_valueList->next();
4417 case CSSPropertyAnimationName:
4418 case CSSPropertyWebkitAnimationName:
4419 currValue = parseAnimationName();
4421 m_valueList->next();
4423 case CSSPropertyAnimationPlayState:
4424 case CSSPropertyWebkitAnimationPlayState:
4425 currValue = parseAnimationPlayState();
4427 m_valueList->next();
4429 case CSSPropertyTransitionProperty:
4430 case CSSPropertyWebkitTransitionProperty:
4431 currValue = parseAnimationProperty(context);
4432 if (value && !context.animationPropertyKeywordAllowed())
4435 m_valueList->next();
4437 case CSSPropertyAnimationTimingFunction:
4438 case CSSPropertyWebkitAnimationTimingFunction:
4439 case CSSPropertyTransitionTimingFunction:
4440 case CSSPropertyWebkitTransitionTimingFunction:
4441 currValue = parseAnimationTimingFunction();
4443 m_valueList->next();
4446 ASSERT_NOT_REACHED();
4453 if (value && !values) {
4454 values = CSSValueList::createCommaSeparated();
4455 values->append(value.release());
4459 values->append(currValue.release());
4461 value = currValue.release();
4466 // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
4472 if (values && values->length()) {
4473 result = values.release();
4477 result = value.release();
4483 // The function parses [ <integer> || <string> ] in <grid-line> (which can be stand alone or with 'span').
4484 bool BisonCSSParser::parseIntegerOrStringFromGridPosition(RefPtrWillBeRawPtr<CSSPrimitiveValue>& numericValue, RefPtrWillBeRawPtr<CSSPrimitiveValue>& gridLineName)
4486 CSSParserValue* value = m_valueList->current();
4487 if (validUnit(value, FInteger) && value->fValue) {
4488 numericValue = createPrimitiveNumericValue(value);
4489 value = m_valueList->next();
4490 if (value && value->unit == CSSPrimitiveValue::CSS_STRING) {
4491 gridLineName = createPrimitiveStringValue(m_valueList->current());
4492 m_valueList->next();
4497 if (value->unit == CSSPrimitiveValue::CSS_STRING) {
4498 gridLineName = createPrimitiveStringValue(m_valueList->current());
4499 value = m_valueList->next();
4500 if (value && validUnit(value, FInteger) && value->fValue) {
4501 numericValue = createPrimitiveNumericValue(value);
4502 m_valueList->next();
4510 PassRefPtr<CSSValue> BisonCSSParser::parseGridPosition()
4512 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4514 CSSParserValue* value = m_valueList->current();
4515 if (value->id == CSSValueAuto) {
4516 m_valueList->next();
4517 return cssValuePool().createIdentifierValue(CSSValueAuto);
4520 if (value->id != CSSValueSpan && value->unit == CSSPrimitiveValue::CSS_IDENT) {
4521 m_valueList->next();
4522 return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
4525 RefPtrWillBeRawPtr<CSSPrimitiveValue> numericValue;
4526 RefPtrWillBeRawPtr<CSSPrimitiveValue> gridLineName;
4527 bool hasSeenSpanKeyword = false;
4529 if (parseIntegerOrStringFromGridPosition(numericValue, gridLineName)) {
4530 value = m_valueList->current();
4531 if (value && value->id == CSSValueSpan) {
4532 hasSeenSpanKeyword = true;
4533 m_valueList->next();
4535 } else if (value->id == CSSValueSpan) {
4536 hasSeenSpanKeyword = true;
4537 if (m_valueList->next())
4538 parseIntegerOrStringFromGridPosition(numericValue, gridLineName);
4541 // Check that we have consumed all the value list. For shorthands, the parser will pass
4542 // the whole value list (including the opposite position).
4543 if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current()))
4546 // If we didn't parse anything, this is not a valid grid position.
4547 if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
4550 // Negative numbers are not allowed for span (but are for <integer>).
4551 if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
4554 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
4555 if (hasSeenSpanKeyword)
4556 values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
4558 values->append(numericValue.release());
4560 values->append(gridLineName.release());
4561 ASSERT(values->length());
4562 return values.release();
4565 static PassRefPtr<CSSValue> gridMissingGridPositionValue(CSSValue* value)
4567 if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isString())
4570 return cssValuePool().createIdentifierValue(CSSValueAuto);
4573 bool BisonCSSParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
4575 ShorthandScope scope(this, shorthandId);
4576 const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
4577 ASSERT(shorthand.length() == 2);
4579 RefPtr<CSSValue> startValue = parseGridPosition();
4583 RefPtr<CSSValue> endValue;
4584 if (m_valueList->current()) {
4585 if (!isForwardSlashOperator(m_valueList->current()))
4588 if (!m_valueList->next())
4591 endValue = parseGridPosition();
4592 if (!endValue || m_valueList->current())
4595 endValue = gridMissingGridPositionValue(startValue.get());
4598 addProperty(shorthand.properties()[0], startValue, important);
4599 addProperty(shorthand.properties()[1], endValue, important);
4603 bool BisonCSSParser::parseGridAreaShorthand(bool important)
4605 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4607 ShorthandScope scope(this, CSSPropertyGridArea);
4608 const StylePropertyShorthand& shorthand = gridAreaShorthand();
4609 ASSERT_UNUSED(shorthand, shorthand.length() == 4);
4611 RefPtr<CSSValue> rowStartValue = parseGridPosition();
4615 RefPtr<CSSValue> columnStartValue;
4616 if (!parseSingleGridAreaLonghand(columnStartValue))
4619 RefPtr<CSSValue> rowEndValue;
4620 if (!parseSingleGridAreaLonghand(rowEndValue))
4623 RefPtr<CSSValue> columnEndValue;
4624 if (!parseSingleGridAreaLonghand(columnEndValue))
4627 if (!columnStartValue)
4628 columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
4631 rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
4633 if (!columnEndValue)
4634 columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
4636 addProperty(CSSPropertyGridRowStart, rowStartValue, important);
4637 addProperty(CSSPropertyGridColumnStart, columnStartValue, important);
4638 addProperty(CSSPropertyGridRowEnd, rowEndValue, important);
4639 addProperty(CSSPropertyGridColumnEnd, columnEndValue, important);
4643 bool BisonCSSParser::parseSingleGridAreaLonghand(RefPtr<CSSValue>& property)
4645 if (!m_valueList->current())
4648 if (!isForwardSlashOperator(m_valueList->current()))
4651 if (!m_valueList->next())
4654 property = parseGridPosition();
4658 void BisonCSSParser::parseGridLineNames(CSSParserValueList* parserValueList, CSSValueList& valueList)
4660 ASSERT(parserValueList->current() && parserValueList->current()->unit == CSSParserValue::ValueList);
4662 CSSParserValueList* identList = parserValueList->current()->valueList;
4663 if (!identList->size()) {
4664 parserValueList->next();
4668 RefPtrWillBeRawPtr<CSSGridLineNamesValue> lineNames = CSSGridLineNamesValue::create();
4669 while (CSSParserValue* identValue = identList->current()) {
4670 ASSERT(identValue->unit == CSSPrimitiveValue::CSS_IDENT);
4671 RefPtrWillBeRawPtr<CSSPrimitiveValue> lineName = createPrimitiveStringValue(identValue);
4672 lineNames->append(lineName.release());
4675 valueList.append(lineNames.release());
4677 parserValueList->next();
4680 bool BisonCSSParser::parseGridTrackList(CSSPropertyID propId, bool important)
4682 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4684 CSSParserValue* value = m_valueList->current();
4685 if (value->id == CSSValueNone) {
4686 if (m_valueList->next())
4689 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
4693 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
4694 // Handle leading <ident>*.
4695 value = m_valueList->current();
4696 if (value && value->unit == CSSParserValue::ValueList)
4697 parseGridLineNames(m_valueList.get(), *values);
4699 bool seenTrackSizeOrRepeatFunction = false;
4700 while (CSSParserValue* currentValue = m_valueList->current()) {
4701 if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "repeat(")) {
4702 if (!parseGridTrackRepeatFunction(*values))
4704 seenTrackSizeOrRepeatFunction = true;
4706 RefPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
4709 values->append(value);
4710 seenTrackSizeOrRepeatFunction = true;
4712 // This will handle the trailing <ident>* in the grammar.
4713 value = m_valueList->current();
4714 if (value && value->unit == CSSParserValue::ValueList)
4715 parseGridLineNames(m_valueList.get(), *values);
4718 // We should have found a <track-size> or else it is not a valid <track-list>
4719 if (!seenTrackSizeOrRepeatFunction)
4722 addProperty(propId, values.release(), important);
4726 bool BisonCSSParser::parseGridTrackRepeatFunction(CSSValueList& list)
4728 CSSParserValueList* arguments = m_valueList->current()->function->args.get();
4729 if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1)))
4732 ASSERT_WITH_SECURITY_IMPLICATION(arguments->valueAt(0)->fValue > 0);
4733 size_t repetitions = arguments->valueAt(0)->fValue;
4734 RefPtrWillBeRawPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
4735 arguments->next(); // Skip the repetition count.
4736 arguments->next(); // Skip the comma.
4738 // Handle leading <ident>*.
4739 CSSParserValue* currentValue = arguments->current();
4740 if (currentValue && currentValue->unit == CSSParserValue::ValueList)
4741 parseGridLineNames(arguments, *repeatedValues);
4743 while (arguments->current()) {
4744 RefPtr<CSSValue> trackSize = parseGridTrackSize(*arguments);
4748 repeatedValues->append(trackSize);
4750 // This takes care of any trailing <ident>* in the grammar.
4751 currentValue = arguments->current();
4752 if (currentValue && currentValue->unit == CSSParserValue::ValueList)
4753 parseGridLineNames(arguments, *repeatedValues);
4756 for (size_t i = 0; i < repetitions; ++i) {
4757 for (size_t j = 0; j < repeatedValues->length(); ++j)
4758 list.append(repeatedValues->itemWithoutBoundsCheck(j));
4761 // parseGridTrackSize iterated over the repeat arguments, move to the next value.
4762 m_valueList->next();
4766 PassRefPtr<CSSValue> BisonCSSParser::parseGridTrackSize(CSSParserValueList& inputList)
4768 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4770 CSSParserValue* currentValue = inputList.current();
4773 if (currentValue->id == CSSValueAuto)
4774 return cssValuePool().createIdentifierValue(CSSValueAuto);
4776 if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax(")) {
4777 // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
4778 CSSParserValueList* arguments = currentValue->function->args.get();
4779 if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
4782 RefPtrWillBeRawPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0));
4783 if (!minTrackBreadth)
4786 RefPtrWillBeRawPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2));
4787 if (!maxTrackBreadth)
4790 RefPtrWillBeRawPtr<CSSValueList> parsedArguments = CSSValueList::createCommaSeparated();
4791 parsedArguments->append(minTrackBreadth);
4792 parsedArguments->append(maxTrackBreadth);
4793 return CSSFunctionValue::create("minmax(", parsedArguments);
4796 return parseGridBreadth(currentValue);
4799 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> BisonCSSParser::parseGridBreadth(CSSParserValue* currentValue)
4801 if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMaxContent)
4802 return cssValuePool().createIdentifierValue(currentValue->id);
4804 if (currentValue->unit == CSSPrimitiveValue::CSS_FR) {
4805 double flexValue = currentValue->fValue;
4807 // Fractional unit is a non-negative dimension.
4811 return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR);
4814 if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
4817 return createPrimitiveNumericValue(currentValue);
4820 PassRefPtr<CSSValue> BisonCSSParser::parseGridTemplateAreas()
4822 NamedGridAreaMap gridAreaMap;
4823 size_t rowCount = 0;
4824 size_t columnCount = 0;
4826 while (CSSParserValue* currentValue = m_valueList->current()) {
4827 if (currentValue->unit != CSSPrimitiveValue::CSS_STRING)
4830 String gridRowNames = currentValue->string;
4831 if (!gridRowNames.length())
4834 Vector<String> columnNames;
4835 gridRowNames.split(' ', columnNames);
4838 columnCount = columnNames.size();
4839 ASSERT(columnCount);
4840 } else if (columnCount != columnNames.size()) {
4841 // The declaration is invalid is all the rows don't have the number of columns.
4845 for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
4846 const String& gridAreaName = columnNames[currentCol];
4848 // Unamed areas are always valid (we consider them to be 1x1).
4849 if (gridAreaName == ".")
4852 // We handle several grid areas with the same name at once to simplify the validation code.
4853 size_t lookAheadCol;
4854 for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++lookAheadCol) {
4855 if (columnNames[lookAheadCol + 1] != gridAreaName)
4859 NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
4860 if (gridAreaIt == gridAreaMap.end()) {
4861 gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowCount), GridSpan(currentCol, lookAheadCol)));
4863 GridCoordinate& gridCoordinate = gridAreaIt->value;
4865 // The following checks test that the grid area is a single filled-in rectangle.
4866 // 1. The new row is adjacent to the previously parsed row.
4867 if (rowCount != gridCoordinate.rows.initialPositionIndex + 1)
4870 // 2. The new area starts at the same position as the previously parsed area.
4871 if (currentCol != gridCoordinate.columns.initialPositionIndex)
4874 // 3. The new area ends at the same position as the previously parsed area.
4875 if (lookAheadCol != gridCoordinate.columns.finalPositionIndex)
4878 ++gridCoordinate.rows.finalPositionIndex;
4880 currentCol = lookAheadCol;
4884 m_valueList->next();
4887 if (!rowCount || !columnCount)
4890 return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
4893 PassRefPtr<CSSValue> BisonCSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
4895 unsigned numArgs = args->size();
4896 if (counters && numArgs != 3 && numArgs != 5)
4898 if (!counters && numArgs != 1 && numArgs != 3)
4901 CSSParserValue* i = args->current();
4902 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
4904 RefPtrWillBeRawPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i);
4906 RefPtrWillBeRawPtr<CSSPrimitiveValue> separator;
4908 separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING);
4911 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
4915 if (i->unit != CSSPrimitiveValue::CSS_STRING)
4918 separator = createPrimitiveStringValue(i);
4921 RefPtrWillBeRawPtr<CSSPrimitiveValue> listStyle;
4923 if (!i) // Make the list style default decimal
4924 listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
4926 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
4930 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
4933 CSSValueID listStyleID = CSSValueInvalid;
4934 if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha))
4935 listStyleID = i->id;
4939 listStyle = cssValuePool().createIdentifierValue(listStyleID);
4942 return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
4945 bool BisonCSSParser::parseClipShape(CSSPropertyID propId, bool important)
4947 CSSParserValue* value = m_valueList->current();
4948 CSSParserValueList* args = value->function->args.get();
4950 if (!equalIgnoringCase(value->function->name, "rect(") || !args)
4953 // rect(t, r, b, l) || rect(t r b l)
4954 if (args->size() != 4 && args->size() != 7)
4956 RefPtr<Rect> rect = Rect::create();
4959 CSSParserValue* a = args->current();
4961 valid = a->id == CSSValueAuto || validUnit(a, FLength);
4964 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
4965 cssValuePool().createIdentifierValue(CSSValueAuto) :
4966 createPrimitiveNumericValue(a);
4968 rect->setTop(length);
4970 rect->setRight(length);
4972 rect->setBottom(length);
4974 rect->setLeft(length);
4976 if (a && args->size() == 7) {
4977 if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
4987 addProperty(propId, cssValuePool().createValue(rect.release()), important);
4988 m_valueList->next();
4994 static void completeBorderRadii(RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[4])
5000 radii[1] = radii[0];
5001 radii[2] = radii[0];
5003 radii[3] = radii[1];
5006 // FIXME: This should be refactored with CSSParser::parseBorderRadius.
5007 // CSSParser::parseBorderRadius contains support for some legacy radius construction.
5008 PassRefPtr<CSSBasicShape> BisonCSSParser::parseInsetRoundedCorners(PassRefPtr<CSSBasicShapeInset> shape, CSSParserValueList* args)
5010 CSSParserValue* argument = args->next();
5015 CSSParserValueList radiusArguments;
5017 radiusArguments.addValue(*argument);
5018 argument = args->next();
5021 unsigned num = radiusArguments.size();
5022 if (!num || num > 9)
5025 // FIXME: Refactor completeBorderRadii and the array
5026 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
5028 unsigned indexAfterSlash = 0;
5029 for (unsigned i = 0; i < num; ++i) {
5030 CSSParserValue* value = radiusArguments.valueAt(i);
5031 if (value->unit == CSSParserValue::Operator) {
5032 if (value->iValue != '/')
5035 if (!i || indexAfterSlash || i + 1 == num)
5038 indexAfterSlash = i + 1;
5039 completeBorderRadii(radii[0]);
5043 if (i - indexAfterSlash >= 4)
5046 if (!validUnit(value, FLength | FPercent | FNonNeg))
5049 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
5051 if (!indexAfterSlash)
5052 radii[0][i] = radius;
5054 radii[1][i - indexAfterSlash] = radius.release();
5057 if (!indexAfterSlash) {
5058 completeBorderRadii(radii[0]);
5059 for (unsigned i = 0; i < 4; ++i)
5060 radii[1][i] = radii[0][i];
5062 completeBorderRadii(radii[1]);
5064 shape->setTopLeftRadius(createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()));
5065 shape->setTopRightRadius(createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()));
5066 shape->setBottomRightRadius(createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()));
5067 shape->setBottomLeftRadius(createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()));
5072 PassRefPtr<CSSBasicShape> BisonCSSParser::parseBasicShapeInset(CSSParserValueList* args)
5076 RefPtr<CSSBasicShapeInset> shape = CSSBasicShapeInset::create();
5078 CSSParserValue* argument = args->current();
5079 WillBeHeapVector<RefPtrWillBeMember<CSSPrimitiveValue> > widthArguments;
5080 bool hasRoundedInset = false;
5083 if (argument->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(argument->string, "round")) {
5084 hasRoundedInset = true;
5088 Units unitFlags = FLength | FPercent;
5089 if (!validUnit(argument, unitFlags) || widthArguments.size() > 4)
5092 widthArguments.append(createPrimitiveNumericValue(argument));
5093 argument = args->next();
5096 switch (widthArguments.size()) {
5098 shape->updateShapeSize1Value(widthArguments[0].get());
5102 shape->updateShapeSize2Values(widthArguments[0].get(), widthArguments[1].get());
5106 shape->updateShapeSize3Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get());
5110 shape->updateShapeSize4Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get(), widthArguments[3].get());
5117 if (hasRoundedInset)
5118 return parseInsetRoundedCorners(shape, args);
5122 static bool isItemPositionKeyword(CSSValueID id)
5124 return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
5125 || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
5126 || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight;
5129 bool BisonCSSParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important)
5131 // auto | baseline | stretch | [<item-position> && <overflow-position>? ]
5132 // <item-position> = center | start | end | self-start | self-end | flex-start | flex-end | left | right;
5133 // <overflow-position> = true | safe
5135 CSSParserValue* value = m_valueList->current();
5137 if (value->id == CSSValueAuto || value->id == CSSValueBaseline || value->id == CSSValueStretch) {
5138 if (m_valueList->next())
5141 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
5145 RefPtrWillBeRawPtr<CSSPrimitiveValue> position = 0;
5146 RefPtrWillBeRawPtr<CSSPrimitiveValue> overflowAlignmentKeyword = 0;
5147 if (isItemPositionKeyword(value->id)) {
5148 position = cssValuePool().createIdentifierValue(value->id);
5149 value = m_valueList->next();
5151 if (value->id == CSSValueTrue || value->id == CSSValueSafe)
5152 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
5156 } else if (value->id == CSSValueTrue || value->id == CSSValueSafe) {
5157 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
5158 value = m_valueList->next();
5160 if (isItemPositionKeyword(value->id))
5161 position = cssValuePool().createIdentifierValue(value->id);
5169 if (m_valueList->next())
5173 if (overflowAlignmentKeyword)
5174 addProperty(propId, createPrimitiveValuePair(position, overflowAlignmentKeyword), important);
5176 addProperty(propId, position.release(), important);
5181 PassRefPtr<CSSBasicShape> BisonCSSParser::parseBasicShapeRectangle(CSSParserValueList* args)
5185 // rect(x, y, width, height, [[rx], ry])
5186 if (args->size() != 7 && args->size() != 9 && args->size() != 11)
5189 RefPtr<CSSBasicShapeRectangle> shape = CSSBasicShapeRectangle::create();
5191 unsigned argumentNumber = 0;
5192 CSSParserValue* argument = args->current();
5194 Units unitFlags = FLength | FPercent;
5195 if (argumentNumber > 1) {
5196 // Arguments width, height, rx, and ry cannot be negative.
5197 unitFlags = unitFlags | FNonNeg;
5199 if (!validUnit(argument, unitFlags))
5202 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5203 ASSERT(argumentNumber < 6);
5204 switch (argumentNumber) {
5206 shape->setX(length);
5209 shape->setY(length);
5212 shape->setWidth(length);
5215 shape->setHeight(length);
5218 shape->setRadiusX(length);
5221 shape->setRadiusY(length);
5224 argument = args->next();
5226 if (!isComma(argument))
5229 argument = args->next();
5234 if (argumentNumber < 4)
5239 PassRefPtr<CSSBasicShape> BisonCSSParser::parseBasicShapeInsetRectangle(CSSParserValueList* args)
5243 // inset-rectangle(top, right, bottom, left, [[rx], ry])
5244 if (args->size() != 7 && args->size() != 9 && args->size() != 11)
5247 RefPtr<CSSBasicShapeInsetRectangle> shape = CSSBasicShapeInsetRectangle::create();
5249 unsigned argumentNumber = 0;
5250 CSSParserValue* argument = args->current();
5252 Units unitFlags = FLength | FPercent | FNonNeg;
5253 if (!validUnit(argument, unitFlags))
5256 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5257 ASSERT(argumentNumber < 6);
5258 switch (argumentNumber) {
5260 shape->setTop(length);
5263 shape->setRight(length);
5266 shape->setBottom(length);
5269 shape->setLeft(length);
5272 shape->setRadiusX(length);
5275 shape->setRadiusY(length);
5278 argument = args->next();
5280 if (!isComma(argument))
5283 argument = args->next();
5288 if (argumentNumber < 4)
5293 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> BisonCSSParser::parseShapeRadius(CSSParserValue* value)
5295 if (value->id == CSSValueClosestSide || value->id == CSSValueFarthestSide)
5296 return cssValuePool().createIdentifierValue(value->id);
5298 if (!validUnit(value, FLength | FPercent | FNonNeg))
5301 return createPrimitiveNumericValue(value);
5304 PassRefPtr<CSSBasicShape> BisonCSSParser::parseBasicShapeCircle(CSSParserValueList* args)
5309 // circle(radius at <position>
5310 // circle(at <position>)
5311 // where position defines centerX and centerY using a CSS <position> data type.
5312 RefPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
5314 for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
5315 // The call to parseFillPosition below should consume all of the
5316 // arguments except the first two. Thus, and index greater than one
5317 // indicates an invalid production.
5318 if (args->currentIndex() > 1)
5321 if (!args->currentIndex() && argument->id != CSSValueAt) {
5322 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
5323 shape->setRadius(radius);
5330 if (argument->id == CSSValueAt) {
5331 RefPtr<CSSValue> centerX;
5332 RefPtr<CSSValue> centerY;
5333 args->next(); // set list to start of position center
5334 parseFillPosition(args, centerX, centerY);
5335 if (centerX && centerY) {
5336 ASSERT(centerX->isPrimitiveValue());
5337 ASSERT(centerY->isPrimitiveValue());
5338 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
5339 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
5351 PassRefPtr<CSSBasicShape> BisonCSSParser::parseDeprecatedBasicShapeCircle(CSSParserValueList* args)
5355 // circle(centerX, centerY, radius)
5356 if (args->size() != 5)
5359 RefPtr<CSSDeprecatedBasicShapeCircle> shape = CSSDeprecatedBasicShapeCircle::create();
5361 unsigned argumentNumber = 0;
5362 CSSParserValue* argument = args->current();
5364 Units unitFlags = FLength | FPercent;
5365 if (argumentNumber == 2) {
5366 // Argument radius cannot be negative.
5367 unitFlags = unitFlags | FNonNeg;
5370 if (!validUnit(argument, unitFlags))
5373 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5374 ASSERT(argumentNumber < 3);
5375 switch (argumentNumber) {
5377 shape->setCenterX(length);
5380 shape->setCenterY(length);
5383 shape->setRadius(length);
5387 argument = args->next();
5389 if (!isComma(argument))
5391 argument = args->next();
5396 if (argumentNumber < 3)
5401 PassRefPtr<CSSBasicShape> BisonCSSParser::parseBasicShapeEllipse(CSSParserValueList* args)
5406 // ellipse(radiusX at <position>
5407 // ellipse(radiusX radiusY)
5408 // ellipse(radiusX radiusY at <position>
5409 // ellipse(at <position>)
5410 // where position defines centerX and centerY using a CSS <position> data type.
5411 RefPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
5413 for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
5414 // The call to parseFillPosition below should consume all of the
5415 // arguments except the first three. Thus, an index greater than two
5416 // indicates an invalid production.
5417 if (args->currentIndex() > 2)
5420 if (args->currentIndex() < 2 && argument->id != CSSValueAt) {
5421 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
5422 if (!shape->radiusX())
5423 shape->setRadiusX(radius);
5425 shape->setRadiusY(radius);
5432 if (argument->id != CSSValueAt)
5434 RefPtr<CSSValue> centerX;
5435 RefPtr<CSSValue> centerY;
5436 args->next(); // set list to start of position center
5437 parseFillPosition(args, centerX, centerY);
5438 if (!centerX || !centerY)
5441 ASSERT(centerX->isPrimitiveValue());
5442 ASSERT(centerY->isPrimitiveValue());
5443 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
5444 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
5450 PassRefPtr<CSSBasicShape> BisonCSSParser::parseDeprecatedBasicShapeEllipse(CSSParserValueList* args)
5454 // ellipse(centerX, centerY, radiusX, radiusY)
5455 if (args->size() != 7)
5458 RefPtr<CSSDeprecatedBasicShapeEllipse> shape = CSSDeprecatedBasicShapeEllipse::create();
5459 unsigned argumentNumber = 0;
5460 CSSParserValue* argument = args->current();
5462 Units unitFlags = FLength | FPercent;
5463 if (argumentNumber > 1) {
5464 // Arguments radiusX and radiusY cannot be negative.
5465 unitFlags = unitFlags | FNonNeg;
5467 if (!validUnit(argument, unitFlags))
5470 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5471 ASSERT(argumentNumber < 4);
5472 switch (argumentNumber) {
5474 shape->setCenterX(length);
5477 shape->setCenterY(length);
5480 shape->setRadiusX(length);
5483 shape->setRadiusY(length);
5487 argument = args->next();
5489 if (!isComma(argument))
5491 argument = args->next();
5496 if (argumentNumber < 4)
5501 PassRefPtr<CSSBasicShape> BisonCSSParser::parseBasicShapePolygon(CSSParserValueList* args)
5505 unsigned size = args->size();
5509 RefPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
5511 CSSParserValue* argument = args->current();
5512 if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
5513 shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
5515 if (!isComma(args->next()))
5518 argument = args->next();
5522 // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one
5523 if (!size || (size % 3) - 2)
5526 CSSParserValue* argumentX = argument;
5528 if (!validUnit(argumentX, FLength | FPercent))
5531 CSSParserValue* argumentY = args->next();
5532 if (!argumentY || !validUnit(argumentY, FLength | FPercent))
5535 RefPtrWillBeRawPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX);
5536 RefPtrWillBeRawPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY);
5538 shape->appendPoint(xLength.release(), yLength.release());
5540 CSSParserValue* commaOrNull = args->next();
5543 else if (!isComma(commaOrNull))
5546 argumentX = args->next();
5552 static bool isBoxValue(CSSValueID valueId)
5555 case CSSValueContentBox:
5556 case CSSValuePaddingBox:
5557 case CSSValueBorderBox:
5558 case CSSValueMarginBox:
5567 // FIXME This function is temporary to allow for an orderly transition between
5568 // the new CSS Shapes circle and ellipse syntax. It will be removed when the
5569 // old syntax is removed.
5570 static bool isDeprecatedBasicShape(CSSParserValueList* args)
5572 for (unsigned i = args->currentIndex(); i < args->size(); ++i) {
5573 CSSParserValue* value = args->valueAt(i);
5581 PassRefPtr<CSSValue> BisonCSSParser::parseShapeProperty(CSSPropertyID propId)
5583 if (!RuntimeEnabledFeatures::cssShapesEnabled())
5586 CSSParserValue* value = m_valueList->current();
5587 CSSValueID valueId = value->id;
5588 RefPtrWillBeRawPtr<CSSPrimitiveValue> boxValue;
5589 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue;
5591 if (valueId == CSSValueNone
5592 || (valueId == CSSValueOutsideShape && propId == CSSPropertyShapeInside)) {
5593 RefPtrWillBeRawPtr<CSSPrimitiveValue> keywordValue = parseValidPrimitive(valueId, value);
5594 m_valueList->next();
5595 return keywordValue.release();
5598 RefPtr<CSSValue> imageValue;
5599 if (valueId != CSSValueNone && parseFillImage(m_valueList.get(), imageValue)) {
5600 m_valueList->next();
5601 return imageValue.release();
5604 if (value->unit == CSSParserValue::Function) {
5605 shapeValue = parseBasicShape();
5608 } else if (isBoxValue(valueId)) {
5609 boxValue = parseValidPrimitive(valueId, value);
5610 m_valueList->next();
5615 ASSERT(shapeValue || boxValue);
5616 value = m_valueList->current();
5619 valueId = value->id;
5620 if (boxValue && value->unit == CSSParserValue::Function) {
5621 shapeValue = parseBasicShape();
5624 } else if (shapeValue && isBoxValue(valueId)) {
5625 boxValue = parseValidPrimitive(valueId, value);
5626 m_valueList->next();
5631 ASSERT(shapeValue && boxValue);
5632 shapeValue->getShapeValue()->setLayoutBox(boxValue.release());
5636 return shapeValue.release();
5637 return boxValue.release();
5640 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> BisonCSSParser::parseBasicShape()
5642 CSSParserValue* value = m_valueList->current();
5643 ASSERT(value->unit == CSSParserValue::Function);
5644 CSSParserValueList* args = value->function->args.get();
5649 RefPtr<CSSBasicShape> shape;
5650 if (equalIgnoringCase(value->function->name, "rectangle("))
5651 shape = parseBasicShapeRectangle(args);
5652 else if (equalIgnoringCase(value->function->name, "circle("))
5653 if (isDeprecatedBasicShape(args))
5654 shape = parseDeprecatedBasicShapeCircle(args);
5656 shape = parseBasicShapeCircle(args);
5657 else if (equalIgnoringCase(value->function->name, "ellipse("))
5658 if (isDeprecatedBasicShape(args))
5659 shape = parseDeprecatedBasicShapeEllipse(args);
5661 shape = parseBasicShapeEllipse(args);
5662 else if (equalIgnoringCase(value->function->name, "polygon("))
5663 shape = parseBasicShapePolygon(args);
5664 else if (equalIgnoringCase(value->function->name, "inset-rectangle("))
5665 shape = parseBasicShapeInsetRectangle(args);
5666 else if (equalIgnoringCase(value->function->name, "inset("))
5667 shape = parseBasicShapeInset(args);
5672 m_valueList->next();
5673 return cssValuePool().createValue(shape.release());
5676 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
5677 bool BisonCSSParser::parseFont(bool important)
5679 // Let's check if there is an inherit or initial somewhere in the shorthand.
5680 for (unsigned i = 0; i < m_valueList->size(); ++i) {
5681 if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial)
5685 ShorthandScope scope(this, CSSPropertyFont);
5686 // Optional font-style, font-variant and font-weight.
5687 bool fontStyleParsed = false;
5688 bool fontVariantParsed = false;
5689 bool fontWeightParsed = false;
5690 CSSParserValue* value;
5691 while ((value = m_valueList->current())) {
5692 if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
5693 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
5694 fontStyleParsed = true;
5695 } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
5696 // Font variant in the shorthand is particular, it only accepts normal or small-caps.
5697 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important);
5698 fontVariantParsed = true;
5699 } else if (!fontWeightParsed && parseFontWeight(important))
5700 fontWeightParsed = true;
5703 m_valueList->next();
5709 if (!fontStyleParsed)
5710 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5711 if (!fontVariantParsed)
5712 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5713 if (!fontWeightParsed)
5714 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5716 // Now a font size _must_ come.
5717 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
5718 if (!parseFontSize(important))
5721 value = m_valueList->current();
5725 if (isForwardSlashOperator(value)) {
5726 // The line-height property.
5727 value = m_valueList->next();
5730 if (!parseLineHeight(important))
5733 addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5735 // Font family must come now.
5736 RefPtr<CSSValue> parsedFamilyValue = parseFontFamily();
5737 if (!parsedFamilyValue)
5740 addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
5742 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
5743 // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
5744 // but we don't seem to support them at the moment. They should also be added here once implemented.
5745 if (m_valueList->current())
5751 class FontFamilyValueBuilder {
5753 FontFamilyValueBuilder(CSSValueList* list)
5758 void add(const CSSParserString& string)
5760 if (!m_builder.isEmpty())
5761 m_builder.append(' ');
5763 if (string.is8Bit()) {
5764 m_builder.append(string.characters8(), string.length());
5768 m_builder.append(string.characters16(), string.length());
5773 if (m_builder.isEmpty())
5775 m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString()));
5780 StringBuilder m_builder;
5781 CSSValueList* m_list;
5784 PassRefPtrWillBeRawPtr<CSSValueList> BisonCSSParser::parseFontFamily()
5786 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
5787 CSSParserValue* value = m_valueList->current();
5789 FontFamilyValueBuilder familyBuilder(list.get());
5790 bool inFamily = false;
5793 CSSParserValue* nextValue = m_valueList->next();
5794 bool nextValBreaksFont = !nextValue ||
5795 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
5796 bool nextValIsFontName = nextValue &&
5797 ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
5798 (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
5800 bool valueIsKeyword = value->id == CSSValueInitial || value->id == CSSValueInherit || value->id == CSSValueDefault;
5801 if (valueIsKeyword && !inFamily) {
5802 if (nextValBreaksFont)
5803 value = m_valueList->next();
5804 else if (nextValIsFontName)
5809 if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
5811 familyBuilder.add(value->string);
5812 else if (nextValBreaksFont || !nextValIsFontName)
5813 list->append(cssValuePool().createIdentifierValue(value->id));
5815 familyBuilder.commit();
5816 familyBuilder.add(value->string);
5819 } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
5820 // Strings never share in a family name.
5822 familyBuilder.commit();
5823 list->append(cssValuePool().createFontFamilyValue(value->string));
5824 } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
5826 familyBuilder.add(value->string);
5827 else if (nextValBreaksFont || !nextValIsFontName)
5828 list->append(cssValuePool().createFontFamilyValue(value->string));
5830 familyBuilder.commit();
5831 familyBuilder.add(value->string);
5841 if (nextValBreaksFont) {
5842 value = m_valueList->next();
5843 familyBuilder.commit();
5846 else if (nextValIsFontName)
5851 familyBuilder.commit();
5853 if (!list->length())
5855 return list.release();
5858 bool BisonCSSParser::parseLineHeight(bool important)
5860 CSSParserValue* value = m_valueList->current();
5861 CSSValueID id = value->id;
5862 bool validPrimitive = false;
5863 // normal | <number> | <length> | <percentage> | inherit
5864 if (id == CSSValueNormal)
5865 validPrimitive = true;
5867 validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
5868 if (validPrimitive && (!m_valueList->next() || inShorthand()))
5869 addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important);
5870 return validPrimitive;
5873 bool BisonCSSParser::parseFontSize(bool important)
5875 CSSParserValue* value = m_valueList->current();
5876 CSSValueID id = value->id;
5877 bool validPrimitive = false;
5878 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
5879 if (id >= CSSValueXxSmall && id <= CSSValueLarger)
5880 validPrimitive = true;
5882 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
5883 if (validPrimitive && (!m_valueList->next() || inShorthand()))
5884 addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important);
5885 return validPrimitive;
5888 bool BisonCSSParser::parseFontVariant(bool important)
5890 RefPtrWillBeRawPtr<CSSValueList> values;
5891 if (m_valueList->size() > 1)
5892 values = CSSValueList::createCommaSeparated();
5893 CSSParserValue* val;
5894 bool expectComma = false;
5895 while ((val = m_valueList->current())) {
5896 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue;
5899 if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
5900 parsedValue = cssValuePool().createIdentifierValue(val->id);
5901 else if (val->id == CSSValueAll && !values) {
5902 // 'all' is only allowed in @font-face and with no other values. Make a value list to
5903 // indicate that we are in the @font-face case.
5904 values = CSSValueList::createCommaSeparated();
5905 parsedValue = cssValuePool().createIdentifierValue(val->id);
5907 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
5908 expectComma = false;
5909 m_valueList->next();
5916 m_valueList->next();
5919 values->append(parsedValue.release());
5921 addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
5926 if (values && values->length()) {
5927 m_hasFontFaceOnlyValues = true;
5928 addProperty(CSSPropertyFontVariant, values.release(), important);
5935 bool BisonCSSParser::parseFontWeight(bool important)
5937 CSSParserValue* value = m_valueList->current();
5938 if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
5939 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important);
5942 if (validUnit(value, FInteger | FNonNeg, HTMLQuirksMode)) {
5943 int weight = static_cast<int>(value->fValue);
5944 if (!(weight % 100) && weight >= 100 && weight <= 900) {
5945 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1)), important);
5952 bool BisonCSSParser::parseFontFaceSrcURI(CSSValueList* valueList)
5954 RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string)));
5956 CSSParserValue* value = m_valueList->next();
5958 valueList->append(uriValue.release());
5961 if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
5962 m_valueList->next();
5963 valueList->append(uriValue.release());
5967 if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format("))
5970 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
5971 // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
5972 CSSParserValueList* args = value->function->args.get();
5973 if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
5975 uriValue->setFormat(args->current()->string);
5976 valueList->append(uriValue.release());
5977 value = m_valueList->next();
5978 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
5979 m_valueList->next();
5983 bool BisonCSSParser::parseFontFaceSrcLocal(CSSValueList* valueList)
5985 CSSParserValueList* args = m_valueList->current()->function->args.get();
5986 if (!args || !args->size())
5989 if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING)
5990 valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string));
5991 else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
5992 StringBuilder builder;
5993 for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) {
5994 if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
5996 if (!builder.isEmpty())
5997 builder.append(' ');
5998 builder.append(localValue->string);
6000 valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
6004 if (CSSParserValue* value = m_valueList->next()) {
6005 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
6006 m_valueList->next();
6011 bool BisonCSSParser::parseFontFaceSrc()
6013 RefPtrWillBeRawPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
6015 while (CSSParserValue* value = m_valueList->current()) {
6016 if (value->unit == CSSPrimitiveValue::CSS_URI) {
6017 if (!parseFontFaceSrcURI(values.get()))
6019 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) {
6020 if (!parseFontFaceSrcLocal(values.get()))
6025 if (!values->length())
6028 addProperty(CSSPropertySrc, values.release(), m_important);
6029 m_valueList->next();
6033 bool BisonCSSParser::parseFontFaceUnicodeRange()
6035 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
6036 bool failed = false;
6037 bool operatorExpected = false;
6038 for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
6039 if (operatorExpected) {
6040 if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
6045 if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
6050 String rangeString = m_valueList->current()->string;
6053 unsigned length = rangeString.length();
6061 while (i < length) {
6062 UChar c = rangeString[i];
6063 if (c == '-' || c == '?')
6066 if (c >= '0' && c <= '9')
6068 else if (c >= 'A' && c <= 'F')
6069 from += 10 + c - 'A';
6070 else if (c >= 'a' && c <= 'f')
6071 from += 10 + c - 'a';
6083 else if (rangeString[i] == '?') {
6085 while (i < length && rangeString[i] == '?') {
6092 to = from + span - 1;
6094 if (length < i + 2) {
6099 while (i < length) {
6100 UChar c = rangeString[i];
6102 if (c >= '0' && c <= '9')
6104 else if (c >= 'A' && c <= 'F')
6106 else if (c >= 'a' && c <= 'f')
6118 values->append(CSSUnicodeRangeValue::create(from, to));
6120 if (failed || !values->length())
6122 addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
6126 // Returns the number of characters which form a valid double
6127 // and are terminated by the given terminator character
6128 template <typename CharacterType>
6129 static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
6131 int length = end - string;
6135 bool decimalMarkSeen = false;
6136 int processedLength = 0;
6138 for (int i = 0; i < length; ++i) {
6139 if (string[i] == terminator) {
6140 processedLength = i;
6143 if (!isASCIIDigit(string[i])) {
6144 if (!decimalMarkSeen && string[i] == '.')
6145 decimalMarkSeen = true;
6151 if (decimalMarkSeen && processedLength == 1)
6154 return processedLength;
6157 // Returns the number of characters consumed for parsing a valid double
6158 // terminated by the given terminator character
6159 template <typename CharacterType>
6160 static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value)
6162 int length = checkForValidDouble(string, end, terminator);
6167 double localValue = 0;
6169 // The consumed characters here are guaranteed to be
6170 // ASCII digits with or without a decimal mark
6171 for (; position < length; ++position) {
6172 if (string[position] == '.')
6174 localValue = localValue * 10 + string[position] - '0';
6177 if (++position == length) {
6182 double fraction = 0;
6185 while (position < length && scale < MAX_SCALE) {
6186 fraction = fraction * 10 + string[position++] - '0';
6190 value = localValue + fraction / scale;
6194 template <typename CharacterType>
6195 static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
6197 const CharacterType* current = string;
6198 double localValue = 0;
6199 bool negative = false;
6200 while (current != end && isHTMLSpace<CharacterType>(*current))
6202 if (current != end && *current == '-') {
6206 if (current == end || !isASCIIDigit(*current))
6208 while (current != end && isASCIIDigit(*current)) {
6209 double newValue = localValue * 10 + *current++ - '0';
6210 if (newValue >= 255) {
6211 // Clamp values at 255.
6213 while (current != end && isASCIIDigit(*current))
6217 localValue = newValue;
6223 if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
6226 if (*current == '.') {
6227 // We already parsed the integral part, try to parse
6228 // the fraction part of the percentage value.
6229 double percentage = 0;
6230 int numCharactersParsed = parseDouble(current, end, '%', percentage);
6231 if (!numCharactersParsed)
6233 current += numCharactersParsed;
6234 if (*current != '%')
6236 localValue += percentage;
6239 if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
6242 if (*current == '%') {
6243 expect = CSSPrimitiveValue::CSS_PERCENTAGE;
6244 localValue = localValue / 100.0 * 256.0;
6245 // Clamp values at 255 for percentages over 100%
6246 if (localValue > 255)
6250 expect = CSSPrimitiveValue::CSS_NUMBER;
6252 while (current != end && isHTMLSpace<CharacterType>(*current))
6254 if (current == end || *current++ != terminator)
6256 // Clamp negative values at zero.
6257 value = negative ? 0 : static_cast<int>(localValue);
6262 template <typename CharacterType>
6263 static inline bool isTenthAlpha(const CharacterType* string, const int length)
6266 if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
6270 if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
6276 template <typename CharacterType>
6277 static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
6279 while (string != end && isHTMLSpace<CharacterType>(*string))
6282 bool negative = false;
6284 if (string != end && *string == '-') {
6291 int length = end - string;
6295 if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
6298 if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
6299 if (checkForValidDouble(string, end, terminator)) {
6300 value = negative ? 0 : 255;
6307 if (length == 2 && string[0] != '.') {
6308 value = !negative && string[0] == '1' ? 255 : 0;
6313 if (isTenthAlpha(string, length - 1)) {
6314 static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
6315 value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
6321 if (!parseDouble(string, end, terminator, alpha))
6323 value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
6328 template <typename CharacterType>
6329 static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
6333 return characters[4] == '('
6334 && isASCIIAlphaCaselessEqual(characters[0], 'r')
6335 && isASCIIAlphaCaselessEqual(characters[1], 'g')
6336 && isASCIIAlphaCaselessEqual(characters[2], 'b')
6337 && isASCIIAlphaCaselessEqual(characters[3], 'a');
6340 template <typename CharacterType>
6341 static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
6345 return characters[3] == '('
6346 && isASCIIAlphaCaselessEqual(characters[0], 'r')
6347 && isASCIIAlphaCaselessEqual(characters[1], 'g')
6348 && isASCIIAlphaCaselessEqual(characters[2], 'b');
6351 template <typename CharacterType>
6352 static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length , bool strict)
6354 CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
6356 if (!strict && length >= 3) {
6357 if (characters[0] == '#') {
6358 if (Color::parseHexColor(characters + 1, length - 1, rgb))
6361 if (Color::parseHexColor(characters, length, rgb))
6366 // Try rgba() syntax.
6367 if (mightBeRGBA(characters, length)) {
6368 const CharacterType* current = characters + 5;
6369 const CharacterType* end = characters + length;
6375 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
6377 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
6379 if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
6381 if (!parseAlphaValue(current, end, ')', alpha))
6385 rgb = makeRGBA(red, green, blue, alpha);
6389 // Try rgb() syntax.
6390 if (mightBeRGB(characters, length)) {
6391 const CharacterType* current = characters + 4;
6392 const CharacterType* end = characters + length;
6396 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
6398 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
6400 if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
6404 rgb = makeRGB(red, green, blue);
6411 template<typename StringType>
6412 bool BisonCSSParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict)
6414 unsigned length = name.length();
6421 parseResult = fastParseColorInternal(rgb, name.characters8(), length, strict);
6423 parseResult = fastParseColorInternal(rgb, name.characters16(), length, strict);
6428 // Try named colors.
6430 if (!tc.setNamedColor(name))
6436 inline double BisonCSSParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc)
6438 const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue;
6439 if (releaseCalc == ReleaseParsedCalcValue)
6440 m_parsedCalculation.release();
6444 bool BisonCSSParser::isCalculation(CSSParserValue* value)
6446 return (value->unit == CSSParserValue::Function)
6447 && (equalIgnoringCase(value->function->name, "calc(")
6448 || equalIgnoringCase(value->function->name, "-webkit-calc(")
6449 || equalIgnoringCase(value->function->name, "-webkit-min(")
6450 || equalIgnoringCase(value->function->name, "-webkit-max("));
6453 inline int BisonCSSParser::colorIntFromValue(CSSParserValue* v)
6457 if (m_parsedCalculation)
6458 isPercent = m_parsedCalculation->category() == CalcPercent;
6460 isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
6462 const double value = parsedDouble(v, ReleaseParsedCalcValue);
6470 return static_cast<int>(value * 256.0 / 100.0);
6476 return static_cast<int>(value);
6479 bool BisonCSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
6481 CSSParserValueList* args = value->function->args.get();
6482 CSSParserValue* v = args->current();
6483 Units unitType = FUnknown;
6484 // Get the first value and its type
6485 if (validUnit(v, FInteger, HTMLStandardMode))
6486 unitType = FInteger;
6487 else if (validUnit(v, FPercent, HTMLStandardMode))
6488 unitType = FPercent;
6492 colorArray[0] = colorIntFromValue(v);
6493 for (int i = 1; i < 3; i++) {
6495 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6498 if (!validUnit(v, unitType, HTMLStandardMode))
6500 colorArray[i] = colorIntFromValue(v);
6504 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6507 if (!validUnit(v, FNumber, HTMLStandardMode))
6509 const double value = parsedDouble(v, ReleaseParsedCalcValue);
6510 // Convert the floating pointer number of alpha to an integer in the range [0, 256),
6511 // with an equal distribution across all 256 values.
6512 colorArray[3] = static_cast<int>(max(0.0, min(1.0, value)) * nextafter(256.0, 0.0));
6517 // The CSS3 specification defines the format of a HSL color as
6518 // hsl(<number>, <percent>, <percent>)
6519 // and with alpha, the format is
6520 // hsla(<number>, <percent>, <percent>, <number>)
6521 // The first value, HUE, is in an angle with a value between 0 and 360
6522 bool BisonCSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
6524 CSSParserValueList* args = value->function->args.get();
6525 CSSParserValue* v = args->current();
6526 // Get the first value
6527 if (!validUnit(v, FNumber, HTMLStandardMode))
6529 // normalize the Hue value and change it to be between 0 and 1.0
6530 colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0;
6531 for (int i = 1; i < 3; i++) {
6533 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6536 if (!validUnit(v, FPercent, HTMLStandardMode))
6538 colorArray[i] = max(0.0, min(100.0, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0
6542 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6545 if (!validUnit(v, FNumber, HTMLStandardMode))
6547 colorArray[3] = max(0.0, min(1.0, parsedDouble(v, ReleaseParsedCalcValue)));
6552 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> BisonCSSParser::parseColor(CSSParserValue* value)
6554 RGBA32 c = Color::transparent;
6555 if (!parseColorFromValue(value ? value : m_valueList->current(), c))
6557 return cssValuePool().createColorValue(c);
6560 bool BisonCSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
6562 if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
6563 && value->fValue >= 0. && value->fValue < 1000000.) {
6564 String str = String::format("%06d", static_cast<int>((value->fValue+.5)));
6565 // FIXME: This should be strict parsing for SVG as well.
6566 if (!fastParseColor(c, str, !inQuirksMode()))
6568 } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
6569 value->unit == CSSPrimitiveValue::CSS_IDENT ||
6570 (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
6571 if (!fastParseColor(c, value->string, !inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
6573 } else if (value->unit == CSSParserValue::Function &&
6574 value->function->args != 0 &&
6575 value->function->args->size() == 5 /* rgb + two commas */ &&
6576 equalIgnoringCase(value->function->name, "rgb(")) {
6578 if (!parseColorParameters(value, colorValues, false))
6580 c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
6582 if (value->unit == CSSParserValue::Function &&
6583 value->function->args != 0 &&
6584 value->function->args->size() == 7 /* rgba + three commas */ &&
6585 equalIgnoringCase(value->function->name, "rgba(")) {
6587 if (!parseColorParameters(value, colorValues, true))
6589 c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
6590 } else if (value->unit == CSSParserValue::Function &&
6591 value->function->args != 0 &&
6592 value->function->args->size() == 5 /* hsl + two commas */ &&
6593 equalIgnoringCase(value->function->name, "hsl(")) {
6594 double colorValues[3];
6595 if (!parseHSLParameters(value, colorValues, false))
6597 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
6598 } else if (value->unit == CSSParserValue::Function &&
6599 value->function->args != 0 &&
6600 value->function->args->size() == 7 /* hsla + three commas */ &&
6601 equalIgnoringCase(value->function->name, "hsla(")) {
6602 double colorValues[4];
6603 if (!parseHSLParameters(value, colorValues, true))
6605 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
6613 // This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return)
6614 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
6615 struct ShadowParseContext {
6616 DISALLOW_ALLOCATION();
6618 ShadowParseContext(CSSPropertyID prop, BisonCSSParser* parser)
6624 , allowSpread(false)
6626 , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
6631 bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
6635 // Handle the ,, case gracefully by doing nothing.
6636 if (x || y || blur || spread || color || style) {
6638 values = CSSValueList::createCommaSeparated();
6640 // Construct the current shadow value and add it to the list.
6641 values->append(CSSShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
6644 // Now reset for the next shadow value.
6657 allowSpread = false;
6658 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6661 void commitLength(CSSParserValue* v)
6663 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
6672 } else if (allowY) {
6677 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6679 } else if (allowBlur) {
6680 blur = val.release();
6682 allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6683 } else if (allowSpread) {
6684 spread = val.release();
6685 allowSpread = false;
6689 void commitColor(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val)
6698 allowSpread = false;
6699 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6703 void commitStyle(CSSParserValue* v)
6705 style = cssValuePool().createIdentifierValue(v->id);
6711 allowSpread = false;
6716 CSSPropertyID property;
6717 BisonCSSParser* m_parser;
6719 RefPtrWillBeRawPtr<CSSValueList> values;
6720 RefPtrWillBeRawPtr<CSSPrimitiveValue> x;
6721 RefPtrWillBeRawPtr<CSSPrimitiveValue> y;
6722 RefPtrWillBeRawPtr<CSSPrimitiveValue> blur;
6723 RefPtrWillBeRawPtr<CSSPrimitiveValue> spread;
6724 RefPtrWillBeRawPtr<CSSPrimitiveValue> style;
6725 RefPtrWillBeRawPtr<CSSPrimitiveValue> color;
6732 bool allowStyle; // inset or not.
6736 PassRefPtrWillBeRawPtr<CSSValueList> BisonCSSParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId)
6738 ShadowParseContext context(propId, this);
6739 CSSParserValue* val;
6740 while ((val = valueList->current())) {
6741 // Check for a comma break first.
6742 if (val->unit == CSSParserValue::Operator) {
6743 if (val->iValue != ',' || !context.allowBreak)
6744 // Other operators aren't legal or we aren't done with the current shadow
6745 // value. Treat as invalid.
6747 // The value is good. Commit it.
6748 context.commitValue();
6749 } else if (validUnit(val, FLength, HTMLStandardMode)) {
6750 // We required a length and didn't get one. Invalid.
6751 if (!context.allowLength())
6754 // Blur radius must be non-negative.
6755 if (context.allowBlur && !validUnit(val, FLength | FNonNeg, HTMLStandardMode))
6758 // A length is allowed here. Construct the value and add it.
6759 context.commitLength(val);
6760 } else if (val->id == CSSValueInset) {
6761 if (!context.allowStyle)
6764 context.commitStyle(val);
6766 // The only other type of value that's ok is a color value.
6767 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedColor;
6768 bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu
6769 || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode())
6770 || val->id == CSSValueCurrentcolor);
6772 if (!context.allowColor)
6774 parsedColor = cssValuePool().createIdentifierValue(val->id);
6778 // It's not built-in. Try to parse it as a color.
6779 parsedColor = parseColor(val);
6781 if (!parsedColor || !context.allowColor)
6782 return 0; // This value is not a color or length and is invalid or
6783 // it is a color, but a color isn't allowed at this point.
6785 context.commitColor(parsedColor.release());
6791 if (context.allowBreak) {
6792 context.commitValue();
6793 if (context.values && context.values->length())
6794 return context.values.release();
6800 bool BisonCSSParser::parseReflect(CSSPropertyID propId, bool important)
6802 // box-reflect: <direction> <offset> <mask>
6804 // Direction comes first.
6805 CSSParserValue* val = m_valueList->current();
6806 RefPtrWillBeRawPtr<CSSPrimitiveValue> direction;
6812 direction = cssValuePool().createIdentifierValue(val->id);
6818 // The offset comes next.
6819 val = m_valueList->next();
6820 RefPtrWillBeRawPtr<CSSPrimitiveValue> offset;
6822 offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6824 if (!validUnit(val, FLength | FPercent))
6826 offset = createPrimitiveNumericValue(val);
6829 // Now for the mask.
6830 RefPtr<CSSValue> mask;
6831 val = m_valueList->next();
6833 mask = parseBorderImage(propId);
6838 RefPtrWillBeRawPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction.release(), offset.release(), mask.release());
6839 addProperty(propId, reflectValue.release(), important);
6840 m_valueList->next();
6844 bool BisonCSSParser::parseFlex(CSSParserValueList* args, bool important)
6846 if (!args || !args->size() || args->size() > 3)
6848 static const double unsetValue = -1;
6849 double flexGrow = unsetValue;
6850 double flexShrink = unsetValue;
6851 RefPtrWillBeRawPtr<CSSPrimitiveValue> flexBasis;
6853 while (CSSParserValue* arg = args->current()) {
6854 if (validUnit(arg, FNumber | FNonNeg)) {
6855 if (flexGrow == unsetValue)
6856 flexGrow = arg->fValue;
6857 else if (flexShrink == unsetValue)
6858 flexShrink = arg->fValue;
6859 else if (!arg->fValue) {
6860 // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
6861 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6863 // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
6866 } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg)))
6867 flexBasis = parseValidPrimitive(arg->id, arg);
6869 // Not a valid arg for flex.
6875 if (flexGrow == unsetValue)
6877 if (flexShrink == unsetValue)
6880 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6882 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
6883 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
6884 addProperty(CSSPropertyFlexBasis, flexBasis, important);
6888 bool BisonCSSParser::parseObjectPosition(bool important)
6890 RefPtr<CSSValue> xValue;
6891 RefPtr<CSSValue> yValue;
6892 parseFillPosition(m_valueList.get(), xValue, yValue);
6893 if (!xValue || !yValue)
6896 CSSPropertyObjectPosition,
6897 createPrimitiveValuePair(toCSSPrimitiveValue(xValue.get()), toCSSPrimitiveValue(yValue.get()), Pair::KeepIdenticalValues),
6902 struct BorderImageParseContext {
6903 DISALLOW_ALLOCATION();
6905 BorderImageParseContext()
6906 : m_canAdvance(false)
6907 , m_allowCommit(true)
6908 , m_allowImage(true)
6909 , m_allowImageSlice(true)
6910 , m_allowRepeat(true)
6911 , m_allowForwardSlashOperator(false)
6912 , m_requireWidth(false)
6913 , m_requireOutset(false)
6916 bool canAdvance() const { return m_canAdvance; }
6917 void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
6919 bool allowCommit() const { return m_allowCommit; }
6920 bool allowImage() const { return m_allowImage; }
6921 bool allowImageSlice() const { return m_allowImageSlice; }
6922 bool allowRepeat() const { return m_allowRepeat; }
6923 bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; }
6925 bool requireWidth() const { return m_requireWidth; }
6926 bool requireOutset() const { return m_requireOutset; }
6928 void commitImage(PassRefPtr<CSSValue> image)
6931 m_canAdvance = true;
6932 m_allowCommit = true;
6933 m_allowImage = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
6934 m_allowImageSlice = !m_imageSlice;
6935 m_allowRepeat = !m_repeat;
6937 void commitImageSlice(PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> slice)
6939 m_imageSlice = slice;
6940 m_canAdvance = true;
6941 m_allowCommit = m_allowForwardSlashOperator = true;
6942 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
6943 m_allowImage = !m_image;
6944 m_allowRepeat = !m_repeat;
6946 void commitForwardSlashOperator()
6948 m_canAdvance = true;
6949 m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowForwardSlashOperator = false;
6950 if (!m_borderSlice) {
6951 m_requireWidth = true;
6952 m_requireOutset = false;
6954 m_requireOutset = true;
6955 m_requireWidth = false;
6958 void commitBorderWidth(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> slice)
6960 m_borderSlice = slice;
6961 m_canAdvance = true;
6962 m_allowCommit = m_allowForwardSlashOperator = true;
6963 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
6964 m_allowImage = !m_image;
6965 m_allowRepeat = !m_repeat;
6967 void commitBorderOutset(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> outset)
6970 m_canAdvance = true;
6971 m_allowCommit = true;
6972 m_allowImageSlice = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
6973 m_allowImage = !m_image;
6974 m_allowRepeat = !m_repeat;
6976 void commitRepeat(PassRefPtr<CSSValue> repeat)
6979 m_canAdvance = true;
6980 m_allowCommit = true;
6981 m_allowRepeat = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
6982 m_allowImageSlice = !m_imageSlice;
6983 m_allowImage = !m_image;
6986 PassRefPtr<CSSValue> commitCSSValue()
6988 return createBorderImageValue(m_image, m_imageSlice, m_borderSlice, m_outset, m_repeat);
6991 void commitMaskBoxImage(BisonCSSParser* parser, bool important)
6993 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSource, parser, m_image, important);
6994 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSlice, parser, m_imageSlice, important);
6995 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageWidth, parser, m_borderSlice, important);
6996 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageOutset, parser, m_outset, important);
6997 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageRepeat, parser, m_repeat, important);
7000 void commitBorderImage(BisonCSSParser* parser, bool important)
7002 commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
7003 commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice, important);
7004 commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice, important);
7005 commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset, important);
7006 commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important);
7009 void commitBorderImageProperty(CSSPropertyID propId, BisonCSSParser* parser, PassRefPtr<CSSValue> value, bool important)
7012 parser->addProperty(propId, value, important);
7014 parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true);
7021 bool m_allowImageSlice;
7023 bool m_allowForwardSlashOperator;
7025 bool m_requireWidth;
7026 bool m_requireOutset;
7028 RefPtr<CSSValue> m_image;
7029 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> m_imageSlice;
7030 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_borderSlice;
7031 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_outset;
7033 RefPtr<CSSValue> m_repeat;
7036 static bool buildBorderImageParseContext(BisonCSSParser& parser, CSSPropertyID propId, BorderImageParseContext& context)
7038 ShorthandScope scope(&parser, propId);
7039 while (CSSParserValue* val = parser.m_valueList->current()) {
7040 context.setCanAdvance(false);
7042 if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(val))
7043 context.commitForwardSlashOperator();
7045 if (!context.canAdvance() && context.allowImage()) {
7046 if (val->unit == CSSPrimitiveValue::CSS_URI) {
7047 context.commitImage(CSSImageValue::create(parser.m_context.completeURL(val->string)));
7048 } else if (isGeneratedImageValue(val)) {
7049 RefPtr<CSSValue> value;
7050 if (parser.parseGeneratedImage(parser.m_valueList.get(), value))
7051 context.commitImage(value.release());
7054 } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
7055 RefPtr<CSSValue> value = parser.parseImageSet(parser.m_valueList.get());
7057 context.commitImage(value.release());
7060 } else if (val->id == CSSValueNone)
7061 context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone));
7064 if (!context.canAdvance() && context.allowImageSlice()) {
7065 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> imageSlice;
7066 if (parser.parseBorderImageSlice(propId, imageSlice))
7067 context.commitImageSlice(imageSlice.release());
7070 if (!context.canAdvance() && context.allowRepeat()) {
7071 RefPtr<CSSValue> repeat;
7072 if (parser.parseBorderImageRepeat(repeat))
7073 context.commitRepeat(repeat.release());
7076 if (!context.canAdvance() && context.requireWidth()) {
7077 RefPtrWillBeRawPtr<CSSPrimitiveValue> borderSlice;
7078 if (parser.parseBorderImageWidth(borderSlice))
7079 context.commitBorderWidth(borderSlice.release());
7082 if (!context.canAdvance() && context.requireOutset()) {
7083 RefPtrWillBeRawPtr<CSSPrimitiveValue> borderOutset;
7084 if (parser.parseBorderImageOutset(borderOutset))
7085 context.commitBorderOutset(borderOutset.release());
7088 if (!context.canAdvance())
7091 parser.m_valueList->next();
7094 return context.allowCommit();
7097 bool BisonCSSParser::parseBorderImageShorthand(CSSPropertyID propId, bool important)
7099 BorderImageParseContext context;
7100 if (buildBorderImageParseContext(*this, propId, context)) {
7102 case CSSPropertyWebkitMaskBoxImage:
7103 context.commitMaskBoxImage(this, important);
7105 case CSSPropertyBorderImage:
7106 context.commitBorderImage(this, important);
7109 ASSERT_NOT_REACHED();
7116 PassRefPtr<CSSValue> BisonCSSParser::parseBorderImage(CSSPropertyID propId)
7118 BorderImageParseContext context;
7119 if (buildBorderImageParseContext(*this, propId, context)) {
7120 return context.commitCSSValue();
7125 static bool isBorderImageRepeatKeyword(int id)
7127 return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
7130 bool BisonCSSParser::parseBorderImageRepeat(RefPtr<CSSValue>& result)
7132 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstValue;
7133 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondValue;
7134 CSSParserValue* val = m_valueList->current();
7137 if (isBorderImageRepeatKeyword(val->id))
7138 firstValue = cssValuePool().createIdentifierValue(val->id);
7142 val = m_valueList->next();
7144 if (isBorderImageRepeatKeyword(val->id))
7145 secondValue = cssValuePool().createIdentifierValue(val->id);
7146 else if (!inShorthand()) {
7147 // If we're not parsing a shorthand then we are invalid.
7150 // We need to rewind the value list, so that when its advanced we'll
7151 // end up back at this value.
7152 m_valueList->previous();
7153 secondValue = firstValue;
7156 secondValue = firstValue;
7158 result = createPrimitiveValuePair(firstValue, secondValue);
7162 class BorderImageSliceParseContext {
7163 DISALLOW_ALLOCATION();
7165 BorderImageSliceParseContext(BisonCSSParser* parser)
7167 , m_allowNumber(true)
7169 , m_allowFinalCommit(false)
7173 bool allowNumber() const { return m_allowNumber; }
7174 bool allowFill() const { return m_allowFill; }
7175 bool allowFinalCommit() const { return m_allowFinalCommit; }
7176 CSSPrimitiveValue* top() const { return m_top.get(); }
7178 void commitNumber(CSSParserValue* v)
7180 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
7192 m_allowNumber = !m_left;
7193 m_allowFinalCommit = true;
7196 void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; }
7198 PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
7200 // We need to clone and repeat values for any omissions.
7214 // Now build a rect value to hold all four of our primitive values.
7215 RefPtr<Quad> quad = Quad::create();
7216 quad->setTop(m_top);
7217 quad->setRight(m_right);
7218 quad->setBottom(m_bottom);
7219 quad->setLeft(m_left);
7221 // Make our new border image value now.
7222 return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill);
7226 BisonCSSParser* m_parser;
7230 bool m_allowFinalCommit;
7232 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_top;
7233 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_right;
7234 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_bottom;
7235 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_left;
7240 bool BisonCSSParser::parseBorderImageSlice(CSSPropertyID propId, RefPtrWillBeRawPtr<CSSBorderImageSliceValue>& result)
7242 BorderImageSliceParseContext context(this);
7243 CSSParserValue* val;
7244 while ((val = m_valueList->current())) {
7245 // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
7246 if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, HTMLStandardMode)) {
7247 context.commitNumber(val);
7248 } else if (context.allowFill() && val->id == CSSValueFill)
7249 context.commitFill();
7250 else if (!inShorthand()) {
7251 // If we're not parsing a shorthand then we are invalid.
7254 if (context.allowFinalCommit()) {
7255 // We're going to successfully parse, but we don't want to consume this token.
7256 m_valueList->previous();
7260 m_valueList->next();
7263 if (context.allowFinalCommit()) {
7264 // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
7265 // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
7266 if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
7267 context.commitFill();
7269 // Need to fully commit as a single value.
7270 result = context.commitBorderImageSlice();
7277 class BorderImageQuadParseContext {
7279 BorderImageQuadParseContext(BisonCSSParser* parser)
7281 , m_allowNumber(true)
7282 , m_allowFinalCommit(false)
7285 bool allowNumber() const { return m_allowNumber; }
7286 bool allowFinalCommit() const { return m_allowFinalCommit; }
7287 CSSPrimitiveValue* top() const { return m_top.get(); }
7289 void commitNumber(CSSParserValue* v)
7291 RefPtrWillBeRawPtr<CSSPrimitiveValue> val;
7292 if (v->id == CSSValueAuto)
7293 val = cssValuePool().createIdentifierValue(v->id);
7295 val = m_parser->createPrimitiveNumericValue(v);
7308 m_allowNumber = !m_left;
7309 m_allowFinalCommit = true;
7312 void setAllowFinalCommit() { m_allowFinalCommit = true; }
7313 void setTop(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val) { m_top = val; }
7315 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> commitBorderImageQuad()
7317 // We need to clone and repeat values for any omissions.
7331 // Now build a quad value to hold all four of our primitive values.
7332 RefPtr<Quad> quad = Quad::create();
7333 quad->setTop(m_top);
7334 quad->setRight(m_right);
7335 quad->setBottom(m_bottom);
7336 quad->setLeft(m_left);
7338 // Make our new value now.
7339 return cssValuePool().createValue(quad.release());
7343 BisonCSSParser* m_parser;
7346 bool m_allowFinalCommit;
7348 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_top;
7349 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_right;
7350 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_bottom;
7351 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_left;
7354 bool BisonCSSParser::parseBorderImageQuad(Units validUnits, RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
7356 BorderImageQuadParseContext context(this);
7357 CSSParserValue* val;
7358 while ((val = m_valueList->current())) {
7359 if (context.allowNumber() && (validUnit(val, validUnits, HTMLStandardMode) || val->id == CSSValueAuto)) {
7360 context.commitNumber(val);
7361 } else if (!inShorthand()) {
7362 // If we're not parsing a shorthand then we are invalid.
7365 if (context.allowFinalCommit())
7366 m_valueList->previous(); // The shorthand loop will advance back to this point.
7369 m_valueList->next();
7372 if (context.allowFinalCommit()) {
7373 // Need to fully commit as a single value.
7374 result = context.commitBorderImageQuad();
7380 bool BisonCSSParser::parseBorderImageWidth(RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
7382 return parseBorderImageQuad(FLength | FNumber | FNonNeg | FPercent, result);
7385 bool BisonCSSParser::parseBorderImageOutset(RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
7387 return parseBorderImageQuad(FLength | FNumber | FNonNeg, result);
7390 bool BisonCSSParser::parseBorderRadius(CSSPropertyID propId, bool important)
7392 unsigned num = m_valueList->size();
7396 ShorthandScope scope(this, propId);
7397 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
7399 unsigned indexAfterSlash = 0;
7400 for (unsigned i = 0; i < num; ++i) {
7401 CSSParserValue* value = m_valueList->valueAt(i);
7402 if (value->unit == CSSParserValue::Operator) {
7403 if (value->iValue != '/')
7406 if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
7409 indexAfterSlash = i + 1;
7410 completeBorderRadii(radii[0]);
7414 if (i - indexAfterSlash >= 4)
7417 if (!validUnit(value, FLength | FPercent | FNonNeg))
7420 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
7422 if (!indexAfterSlash) {
7423 radii[0][i] = radius;
7425 // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
7426 if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
7427 indexAfterSlash = 1;
7428 completeBorderRadii(radii[0]);
7431 radii[1][i - indexAfterSlash] = radius.release();
7434 if (!indexAfterSlash) {
7435 completeBorderRadii(radii[0]);
7436 for (unsigned i = 0; i < 4; ++i)
7437 radii[1][i] = radii[0][i];
7439 completeBorderRadii(radii[1]);
7441 ImplicitScope implicitScope(this, PropertyImplicit);
7442 addProperty(CSSPropertyBorderTopLeftRadius, createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()), important);
7443 addProperty(CSSPropertyBorderTopRightRadius, createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()), important);
7444 addProperty(CSSPropertyBorderBottomRightRadius, createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()), important);
7445 addProperty(CSSPropertyBorderBottomLeftRadius, createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()), important);
7449 bool BisonCSSParser::parseAspectRatio(bool important)
7451 unsigned num = m_valueList->size();
7452 if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
7453 addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(CSSValueNone), important);
7460 CSSParserValue* lvalue = m_valueList->valueAt(0);
7461 CSSParserValue* op = m_valueList->valueAt(1);
7462 CSSParserValue* rvalue = m_valueList->valueAt(2);
7464 if (!isForwardSlashOperator(op))
7467 if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
7470 if (!lvalue->fValue || !rvalue->fValue)
7473 addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important);
7478 bool BisonCSSParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important)
7480 enum { ID, VAL } state = ID;
7482 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
7483 RefPtrWillBeRawPtr<CSSPrimitiveValue> counterName;
7486 CSSParserValue* val = m_valueList->current();
7489 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
7490 counterName = createPrimitiveStringValue(val);
7492 m_valueList->next();
7497 int i = defaultValue;
7498 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
7499 i = clampToInteger(val->fValue);
7500 m_valueList->next();
7503 list->append(createPrimitiveValuePair(counterName.release(),
7504 cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER)));
7512 if (list->length() > 0) {
7513 addProperty(propId, list.release(), important);
7520 // This should go away once we drop support for -webkit-gradient
7521 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
7523 RefPtrWillBeRawPtr<CSSPrimitiveValue> result;
7524 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
7525 if ((equalIgnoringCase(a, "left") && horizontal)
7526 || (equalIgnoringCase(a, "top") && !horizontal))
7527 result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
7528 else if ((equalIgnoringCase(a, "right") && horizontal)
7529 || (equalIgnoringCase(a, "bottom") && !horizontal))
7530 result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
7531 else if (equalIgnoringCase(a, "center"))
7532 result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
7533 } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7534 result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(a->unit));
7538 static bool parseDeprecatedGradientColorStop(BisonCSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
7540 if (a->unit != CSSParserValue::Function)
7543 if (!equalIgnoringCase(a->function->name, "from(") &&
7544 !equalIgnoringCase(a->function->name, "to(") &&
7545 !equalIgnoringCase(a->function->name, "color-stop("))
7548 CSSParserValueList* args = a->function->args.get();
7552 if (equalIgnoringCase(a->function->name, "from(")
7553 || equalIgnoringCase(a->function->name, "to(")) {
7554 // The "from" and "to" stops expect 1 argument.
7555 if (args->size() != 1)
7558 if (equalIgnoringCase(a->function->name, "from("))
7559 stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
7561 stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
7563 CSSValueID id = args->current()->id;
7564 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
7565 stop.m_color = cssValuePool().createIdentifierValue(id);
7567 stop.m_color = p->parseColor(args->current());
7572 // The "color-stop" function expects 3 arguments.
7573 if (equalIgnoringCase(a->function->name, "color-stop(")) {
7574 if (args->size() != 3)
7577 CSSParserValue* stopArg = args->current();
7578 if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7579 stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
7580 else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
7581 stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
7585 stopArg = args->next();
7586 if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
7589 stopArg = args->next();
7590 CSSValueID id = stopArg->id;
7591 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
7592 stop.m_color = cssValuePool().createIdentifierValue(id);
7594 stop.m_color = p->parseColor(stopArg);
7602 bool BisonCSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient)
7604 // Walk the arguments.
7605 CSSParserValueList* args = valueList->current()->function->args.get();
7606 if (!args || args->size() == 0)
7609 // The first argument is the gradient type. It is an identifier.
7610 CSSGradientType gradientType;
7611 CSSParserValue* a = args->current();
7612 if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
7614 if (equalIgnoringCase(a, "linear"))
7615 gradientType = CSSDeprecatedLinearGradient;
7616 else if (equalIgnoringCase(a, "radial"))
7617 gradientType = CSSDeprecatedRadialGradient;
7621 RefPtr<CSSGradientValue> result;
7622 switch (gradientType) {
7623 case CSSDeprecatedLinearGradient:
7624 result = CSSLinearGradientValue::create(NonRepeating, gradientType);
7626 case CSSDeprecatedRadialGradient:
7627 result = CSSRadialGradientValue::create(NonRepeating, gradientType);
7630 // The rest of the gradient types shouldn't appear here.
7631 ASSERT_NOT_REACHED();
7639 // Next comes the starting point for the gradient as an x y pair. There is no
7640 // comma between the x and the y values.
7641 // First X. It can be left, right, number or percent.
7645 RefPtrWillBeRawPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
7648 result->setFirstX(point.release());
7650 // First Y. It can be top, bottom, number or percent.
7654 point = parseDeprecatedGradientPoint(a, false);
7657 result->setFirstY(point.release());
7659 // Comma after the first point.
7664 // For radial gradients only, we now expect a numeric radius.
7665 if (gradientType == CSSDeprecatedRadialGradient) {
7667 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
7669 toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
7671 // Comma after the first radius.
7677 // Next is the ending point for the gradient as an x, y pair.
7678 // Second X. It can be left, right, number or percent.
7682 point = parseDeprecatedGradientPoint(a, true);
7685 result->setSecondX(point.release());
7687 // Second Y. It can be top, bottom, number or percent.
7691 point = parseDeprecatedGradientPoint(a, false);
7694 result->setSecondY(point.release());
7696 // For radial gradients only, we now expect the second radius.
7697 if (gradientType == CSSDeprecatedRadialGradient) {
7698 // Comma after the second point.
7704 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
7706 toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
7709 // We now will accept any number of stops (0 or more).
7712 // Look for the comma before the next stop.
7716 // Now examine the stop itself.
7721 // The function name needs to be one of "from", "to", or "color-stop."
7722 CSSGradientColorStop stop;
7723 if (!parseDeprecatedGradientColorStop(this, a, stop))
7725 result->addStop(stop);
7731 gradient = result.release();
7735 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
7737 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
7743 isHorizontal = true;
7746 case CSSValueBottom:
7747 isHorizontal = false;
7752 return cssValuePool().createIdentifierValue(a->id);
7755 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(BisonCSSParser* p, CSSParserValue* value)
7757 CSSValueID id = value->id;
7758 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
7759 return cssValuePool().createIdentifierValue(id);
7761 return p->parseColor(value);
7764 bool BisonCSSParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7766 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient);
7768 // Walk the arguments.
7769 CSSParserValueList* args = valueList->current()->function->args.get();
7770 if (!args || !args->size())
7773 CSSParserValue* a = args->current();
7777 bool expectComma = false;
7779 if (validUnit(a, FAngle, HTMLStandardMode)) {
7780 result->setAngle(createPrimitiveNumericValue(a));
7785 // Look one or two optional keywords that indicate a side or corner.
7786 RefPtrWillBeRawPtr<CSSPrimitiveValue> startX, startY;
7788 RefPtrWillBeRawPtr<CSSPrimitiveValue> location;
7789 bool isHorizontal = false;
7790 if ((location = valueFromSideKeyword(a, isHorizontal))) {
7796 if ((a = args->next())) {
7797 if ((location = valueFromSideKeyword(a, isHorizontal))) {
7815 if (!startX && !startY)
7816 startY = cssValuePool().createIdentifierValue(CSSValueTop);
7818 result->setFirstX(startX.release());
7819 result->setFirstY(startY.release());
7822 if (!parseGradientColorStops(args, result.get(), expectComma))
7825 if (!result->stopCount())
7828 gradient = result.release();
7832 bool BisonCSSParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7834 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
7836 // Walk the arguments.
7837 CSSParserValueList* args = valueList->current()->function->args.get();
7838 if (!args || !args->size())
7841 CSSParserValue* a = args->current();
7845 bool expectComma = false;
7847 // Optional background-position
7848 RefPtr<CSSValue> centerX;
7849 RefPtr<CSSValue> centerY;
7850 // parse2ValuesFillPosition advances the args next pointer.
7851 parse2ValuesFillPosition(args, centerX, centerY);
7852 a = args->current();
7856 if (centerX || centerY) {
7866 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
7867 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
7868 // CSS3 radial gradients always share the same start and end point.
7869 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
7870 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
7872 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue;
7873 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue;
7875 // Optional shape and/or size in any order.
7876 for (int i = 0; i < 2; ++i) {
7877 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
7880 bool foundValue = false;
7882 case CSSValueCircle:
7883 case CSSValueEllipse:
7884 shapeValue = cssValuePool().createIdentifierValue(a->id);
7887 case CSSValueClosestSide:
7888 case CSSValueClosestCorner:
7889 case CSSValueFarthestSide:
7890 case CSSValueFarthestCorner:
7891 case CSSValueContain:
7893 sizeValue = cssValuePool().createIdentifierValue(a->id);
7909 result->setShape(shapeValue);
7910 result->setSizingBehavior(sizeValue);
7912 // Or, two lengths or percentages
7913 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize;
7914 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize;
7916 if (!shapeValue && !sizeValue) {
7917 if (validUnit(a, FLength | FPercent)) {
7918 horizontalSize = createPrimitiveNumericValue(a);
7926 if (validUnit(a, FLength | FPercent)) {
7927 verticalSize = createPrimitiveNumericValue(a);
7936 // Must have neither or both.
7937 if (!horizontalSize != !verticalSize)
7940 result->setEndHorizontalSize(horizontalSize);
7941 result->setEndVerticalSize(verticalSize);
7943 if (!parseGradientColorStops(args, result.get(), expectComma))
7946 gradient = result.release();
7950 bool BisonCSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7952 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient);
7954 CSSParserValueList* args = valueList->current()->function->args.get();
7955 if (!args || !args->size())
7958 CSSParserValue* a = args->current();
7962 bool expectComma = false;
7964 if (validUnit(a, FAngle, HTMLStandardMode)) {
7965 result->setAngle(createPrimitiveNumericValue(a));
7969 } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) {
7970 // to [ [left | right] || [top | bottom] ]
7975 RefPtrWillBeRawPtr<CSSPrimitiveValue> endX, endY;
7976 RefPtrWillBeRawPtr<CSSPrimitiveValue> location;
7977 bool isHorizontal = false;
7979 location = valueFromSideKeyword(a, isHorizontal);
7992 location = valueFromSideKeyword(a, isHorizontal);
8008 result->setFirstX(endX.release());
8009 result->setFirstY(endY.release());
8012 if (!parseGradientColorStops(args, result.get(), expectComma))
8015 if (!result->stopCount())
8018 gradient = result.release();
8022 bool BisonCSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
8024 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
8026 CSSParserValueList* args = valueList->current()->function->args.get();
8027 if (!args || !args->size())
8030 CSSParserValue* a = args->current();
8034 bool expectComma = false;
8036 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue;
8037 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue;
8038 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize;
8039 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize;
8041 // First part of grammar, the size/shape clause:
8042 // [ circle || <length> ] |
8043 // [ ellipse || [ <length> | <percentage> ]{2} ] |
8044 // [ [ circle | ellipse] || <size-keyword> ]
8045 for (int i = 0; i < 3; ++i) {
8046 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
8047 bool badIdent = false;
8049 case CSSValueCircle:
8050 case CSSValueEllipse:
8053 shapeValue = cssValuePool().createIdentifierValue(a->id);
8055 case CSSValueClosestSide:
8056 case CSSValueClosestCorner:
8057 case CSSValueFarthestSide:
8058 case CSSValueFarthestCorner:
8059 if (sizeValue || horizontalSize)
8061 sizeValue = cssValuePool().createIdentifierValue(a->id);
8073 } else if (validUnit(a, FLength | FPercent)) {
8075 if (sizeValue || horizontalSize)
8077 horizontalSize = createPrimitiveNumericValue(a);
8083 if (validUnit(a, FLength | FPercent)) {
8084 verticalSize = createPrimitiveNumericValue(a);
8094 // You can specify size as a keyword or a length/percentage, not both.
8095 if (sizeValue && horizontalSize)
8097 // Circles must have 0 or 1 lengths.
8098 if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize)
8100 // Ellipses must have 0 or 2 length/percentages.
8101 if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
8103 // If there's only one size, it must be a length.
8104 if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
8107 result->setShape(shapeValue);
8108 result->setSizingBehavior(sizeValue);
8109 result->setEndHorizontalSize(horizontalSize);
8110 result->setEndVerticalSize(verticalSize);
8112 // Second part of grammar, the center-position clause:
8114 RefPtr<CSSValue> centerX;
8115 RefPtr<CSSValue> centerY;
8116 if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) {
8121 parseFillPosition(args, centerX, centerY);
8122 if (!(centerX && centerY))
8125 a = args->current();
8128 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
8129 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
8130 // Right now, CSS radial gradients have the same start and end centers.
8131 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
8132 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
8135 if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
8138 if (!parseGradientColorStops(args, result.get(), expectComma))
8141 gradient = result.release();
8145 bool BisonCSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
8147 CSSParserValue* a = valueList->current();
8149 // Now look for color stops.
8151 // Look for the comma before the next stop.
8156 a = valueList->next();
8161 // <color-stop> = <color> [ <percentage> | <length> ]?
8162 CSSGradientColorStop stop;
8163 stop.m_color = parseGradientColorOrKeyword(this, a);
8167 a = valueList->next();
8169 if (validUnit(a, FLength | FPercent)) {
8170 stop.m_position = createPrimitiveNumericValue(a);
8171 a = valueList->next();
8175 gradient->addStop(stop);
8179 // Must have 2 or more stops to be valid.
8180 return gradient->stopCount() >= 2;
8183 bool BisonCSSParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
8185 CSSParserValue* val = valueList->current();
8187 if (val->unit != CSSParserValue::Function)
8190 if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) {
8191 // FIXME: This should send a deprecation message.
8192 if (m_context.useCounter())
8193 m_context.useCounter()->count(UseCounter::DeprecatedWebKitGradient);
8194 return parseDeprecatedGradient(valueList, value);
8197 if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")) {
8198 // FIXME: This should send a deprecation message.
8199 if (m_context.useCounter())
8200 m_context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGradient);
8201 return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
8204 if (equalIgnoringCase(val->function->name, "linear-gradient("))
8205 return parseLinearGradient(valueList, value, NonRepeating);
8207 if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")) {
8208 // FIXME: This should send a deprecation message.
8209 if (m_context.useCounter())
8210 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLinearGradient);
8211 return parseDeprecatedLinearGradient(valueList, value, Repeating);
8214 if (equalIgnoringCase(val->function->name, "repeating-linear-gradient("))
8215 return parseLinearGradient(valueList, value, Repeating);
8217 if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")) {
8218 // FIXME: This should send a deprecation message.
8219 if (m_context.useCounter())
8220 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGradient);
8221 return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
8224 if (equalIgnoringCase(val->function->name, "radial-gradient("))
8225 return parseRadialGradient(valueList, value, NonRepeating);
8227 if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")) {
8228 if (m_context.useCounter())
8229 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingRadialGradient);
8230 return parseDeprecatedRadialGradient(valueList, value, Repeating);
8233 if (equalIgnoringCase(val->function->name, "repeating-radial-gradient("))
8234 return parseRadialGradient(valueList, value, Repeating);
8236 if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
8237 return parseCanvas(valueList, value);
8239 if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
8240 return parseCrossfade(valueList, value);
8245 bool BisonCSSParser::parseCrossfade(CSSParserValueList* valueList, RefPtr<CSSValue>& crossfade)
8247 // Walk the arguments.
8248 CSSParserValueList* args = valueList->current()->function->args.get();
8249 if (!args || args->size() != 5)
8251 CSSParserValue* a = args->current();
8252 RefPtr<CSSValue> fromImageValue;
8253 RefPtr<CSSValue> toImageValue;
8255 // The first argument is the "from" image. It is a fill image.
8256 if (!a || !parseFillImage(args, fromImageValue))
8265 // The second argument is the "to" image. It is a fill image.
8266 if (!a || !parseFillImage(args, toImageValue))
8275 // The third argument is the crossfade value. It is a percentage or a fractional number.
8276 RefPtrWillBeRawPtr<CSSPrimitiveValue> percentage;
8280 if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
8281 percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
8282 else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
8283 percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
8287 RefPtrWillBeRawPtr<CSSCrossfadeValue> result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
8288 result->setPercentage(percentage);
8295 bool BisonCSSParser::parseCanvas(CSSParserValueList* valueList, RefPtr<CSSValue>& canvas)
8297 // Walk the arguments.
8298 CSSParserValueList* args = valueList->current()->function->args.get();
8299 if (!args || args->size() != 1)
8302 // The first argument is the canvas name. It is an identifier.
8303 CSSParserValue* value = args->current();
8304 if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
8307 canvas = CSSCanvasValue::create(value->string);
8311 PassRefPtr<CSSValue> BisonCSSParser::parseImageSet(CSSParserValueList* valueList)
8313 CSSParserValue* function = valueList->current();
8315 if (function->unit != CSSParserValue::Function)
8318 CSSParserValueList* functionArgs = valueList->current()->function->args.get();
8319 if (!functionArgs || !functionArgs->size() || !functionArgs->current())
8322 RefPtrWillBeRawPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
8324 CSSParserValue* arg = functionArgs->current();
8326 if (arg->unit != CSSPrimitiveValue::CSS_URI)
8329 RefPtr<CSSImageValue> image = CSSImageValue::create(completeURL(arg->string));
8330 imageSet->append(image);
8332 arg = functionArgs->next();
8333 if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
8336 double imageScaleFactor = 0;
8337 const String& string = arg->string;
8338 unsigned length = string.length();
8341 if (string.is8Bit()) {
8342 const LChar* start = string.characters8();
8343 parseDouble(start, start + length, 'x', imageScaleFactor);
8345 const UChar* start = string.characters16();
8346 parseDouble(start, start + length, 'x', imageScaleFactor);
8348 if (imageScaleFactor <= 0)
8350 imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER));
8352 // If there are no more arguments, we're done.
8353 arg = functionArgs->next();
8357 // If there are more arguments, they should be after a comma.
8361 // Skip the comma and move on to the next argument.
8362 arg = functionArgs->next();
8365 return imageSet.release();
8368 class TransformOperationInfo {
8370 TransformOperationInfo(const CSSParserString& name)
8371 : m_type(CSSTransformValue::UnknownTransformOperation)
8373 , m_allowSingleArgument(false)
8374 , m_unit(BisonCSSParser::FUnknown)
8376 const UChar* characters;
8377 unsigned nameLength = name.length();
8379 const unsigned longestNameLength = 12;
8380 UChar characterBuffer[longestNameLength];
8381 if (name.is8Bit()) {
8382 unsigned length = std::min(longestNameLength, nameLength);
8383 const LChar* characters8 = name.characters8();
8384 for (unsigned i = 0; i < length; ++i)
8385 characterBuffer[i] = characters8[i];
8386 characters = characterBuffer;
8388 characters = name.characters16();
8390 SWITCH(characters, nameLength) {
8392 m_unit = BisonCSSParser::FAngle;
8393 m_type = CSSTransformValue::SkewTransformOperation;
8394 m_allowSingleArgument = true;
8398 m_unit = BisonCSSParser::FNumber;
8399 m_type = CSSTransformValue::ScaleTransformOperation;
8400 m_allowSingleArgument = true;
8404 m_unit = BisonCSSParser::FAngle;
8405 m_type = CSSTransformValue::SkewXTransformOperation;
8408 m_unit = BisonCSSParser::FAngle;
8409 m_type = CSSTransformValue::SkewYTransformOperation;
8412 m_unit = BisonCSSParser::FNumber;
8413 m_type = CSSTransformValue::MatrixTransformOperation;
8417 m_unit = BisonCSSParser::FAngle;
8418 m_type = CSSTransformValue::RotateTransformOperation;
8421 m_unit = BisonCSSParser::FNumber;
8422 m_type = CSSTransformValue::ScaleXTransformOperation;
8425 m_unit = BisonCSSParser::FNumber;
8426 m_type = CSSTransformValue::ScaleYTransformOperation;
8429 m_unit = BisonCSSParser::FNumber;
8430 m_type = CSSTransformValue::ScaleZTransformOperation;
8433 m_unit = BisonCSSParser::FNumber;
8434 m_type = CSSTransformValue::Scale3DTransformOperation;
8438 m_unit = BisonCSSParser::FAngle;
8439 m_type = CSSTransformValue::RotateXTransformOperation;
8442 m_unit = BisonCSSParser::FAngle;
8443 m_type = CSSTransformValue::RotateYTransformOperation;
8446 m_unit = BisonCSSParser::FAngle;
8447 m_type = CSSTransformValue::RotateZTransformOperation;
8450 m_unit = BisonCSSParser::FNumber;
8451 m_type = CSSTransformValue::Matrix3DTransformOperation;
8455 m_unit = BisonCSSParser::FNumber;
8456 m_type = CSSTransformValue::Rotate3DTransformOperation;
8459 CASE("translate(") {
8460 m_unit = BisonCSSParser::FLength | BisonCSSParser::FPercent;
8461 m_type = CSSTransformValue::TranslateTransformOperation;
8462 m_allowSingleArgument = true;
8465 CASE("translatex(") {
8466 m_unit = BisonCSSParser::FLength | BisonCSSParser::FPercent;
8467 m_type = CSSTransformValue::TranslateXTransformOperation;
8469 CASE("translatey(") {
8470 m_unit = BisonCSSParser::FLength | BisonCSSParser::FPercent;
8471 m_type = CSSTransformValue::TranslateYTransformOperation;
8473 CASE("translatez(") {
8474 m_unit = BisonCSSParser::FLength | BisonCSSParser::FPercent;
8475 m_type = CSSTransformValue::TranslateZTransformOperation;
8477 CASE("perspective(") {
8478 m_unit = BisonCSSParser::FNumber;
8479 m_type = CSSTransformValue::PerspectiveTransformOperation;
8481 CASE("translate3d(") {
8482 m_unit = BisonCSSParser::FLength | BisonCSSParser::FPercent;
8483 m_type = CSSTransformValue::Translate3DTransformOperation;
8489 CSSTransformValue::TransformOperationType type() const { return m_type; }
8490 unsigned argCount() const { return m_argCount; }
8491 BisonCSSParser::Units unit() const { return m_unit; }
8493 bool unknown() const { return m_type == CSSTransformValue::UnknownTransformOperation; }
8494 bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
8497 CSSTransformValue::TransformOperationType m_type;
8498 unsigned m_argCount;
8499 bool m_allowSingleArgument;
8500 BisonCSSParser::Units m_unit;
8503 PassRefPtrWillBeRawPtr<CSSValueList> BisonCSSParser::parseTransform()
8508 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8509 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
8510 RefPtr<CSSValue> parsedTransformValue = parseTransformValue(value);
8511 if (!parsedTransformValue)
8514 list->append(parsedTransformValue.release());
8517 return list.release();
8520 PassRefPtr<CSSValue> BisonCSSParser::parseTransformValue(CSSParserValue *value)
8522 if (value->unit != CSSParserValue::Function || !value->function)
8525 // Every primitive requires at least one argument.
8526 CSSParserValueList* args = value->function->args.get();
8530 // See if the specified primitive is one we understand.
8531 TransformOperationInfo info(value->function->name);
8535 if (!info.hasCorrectArgCount(args->size()))
8538 // The transform is a list of functional primitives that specify transform operations.
8539 // We collect a list of CSSTransformValues, where each value specifies a single operation.
8541 // Create the new CSSTransformValue for this operation and add it to our list.
8542 RefPtrWillBeRawPtr<CSSTransformValue> transformValue = CSSTransformValue::create(info.type());
8545 CSSParserValue* a = args->current();
8546 unsigned argNumber = 0;
8548 BisonCSSParser::Units unit = info.unit();
8550 if (info.type() == CSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
8551 // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
8552 if (!validUnit(a, FAngle, HTMLStandardMode))
8554 } else if (info.type() == CSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
8555 // 3rd param of translate3d() cannot be a percentage
8556 if (!validUnit(a, FLength, HTMLStandardMode))
8558 } else if (info.type() == CSSTransformValue::TranslateZTransformOperation && !argNumber) {
8559 // 1st param of translateZ() cannot be a percentage
8560 if (!validUnit(a, FLength, HTMLStandardMode))
8562 } else if (info.type() == CSSTransformValue::PerspectiveTransformOperation && !argNumber) {
8563 // 1st param of perspective() must be a non-negative number (deprecated) or length.
8564 if (!validUnit(a, FNumber | FLength | FNonNeg, HTMLStandardMode))
8566 } else if (!validUnit(a, unit, HTMLStandardMode))
8569 // Add the value to the current transform operation.
8570 transformValue->append(createPrimitiveNumericValue(a));
8575 if (a->unit != CSSParserValue::Operator || a->iValue != ',')
8582 return transformValue.release();
8585 bool BisonCSSParser::isBlendMode(CSSValueID valueID)
8587 return (valueID >= CSSValueMultiply && valueID <= CSSValueLuminosity)
8588 || valueID == CSSValueNormal
8589 || valueID == CSSValueOverlay;
8592 bool BisonCSSParser::isCompositeOperator(CSSValueID valueID)
8594 // FIXME: Add CSSValueDestination and CSSValueLighter when the Compositing spec updates.
8595 return valueID >= CSSValueClear && valueID <= CSSValueXor;
8598 static void filterInfoForName(const CSSParserString& name, CSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
8600 if (equalIgnoringCase(name, "grayscale("))
8601 filterType = CSSFilterValue::GrayscaleFilterOperation;
8602 else if (equalIgnoringCase(name, "sepia("))
8603 filterType = CSSFilterValue::SepiaFilterOperation;
8604 else if (equalIgnoringCase(name, "saturate("))
8605 filterType = CSSFilterValue::SaturateFilterOperation;
8606 else if (equalIgnoringCase(name, "hue-rotate("))
8607 filterType = CSSFilterValue::HueRotateFilterOperation;
8608 else if (equalIgnoringCase(name, "invert("))
8609 filterType = CSSFilterValue::InvertFilterOperation;
8610 else if (equalIgnoringCase(name, "opacity("))
8611 filterType = CSSFilterValue::OpacityFilterOperation;
8612 else if (equalIgnoringCase(name, "brightness("))
8613 filterType = CSSFilterValue::BrightnessFilterOperation;
8614 else if (equalIgnoringCase(name, "contrast("))
8615 filterType = CSSFilterValue::ContrastFilterOperation;
8616 else if (equalIgnoringCase(name, "blur("))
8617 filterType = CSSFilterValue::BlurFilterOperation;
8618 else if (equalIgnoringCase(name, "drop-shadow(")) {
8619 filterType = CSSFilterValue::DropShadowFilterOperation;
8620 maximumArgumentCount = 4; // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
8624 PassRefPtrWillBeRawPtr<CSSFilterValue> BisonCSSParser::parseBuiltinFilterArguments(CSSParserValueList* args, CSSFilterValue::FilterOperationType filterType)
8626 RefPtrWillBeRawPtr<CSSFilterValue> filterValue = CSSFilterValue::create(filterType);
8629 switch (filterType) {
8630 case CSSFilterValue::GrayscaleFilterOperation:
8631 case CSSFilterValue::SepiaFilterOperation:
8632 case CSSFilterValue::SaturateFilterOperation:
8633 case CSSFilterValue::InvertFilterOperation:
8634 case CSSFilterValue::OpacityFilterOperation:
8635 case CSSFilterValue::ContrastFilterOperation: {
8636 // One optional argument, 0-1 or 0%-100%, if missing use 100%.
8637 if (args->size() > 1)
8641 CSSParserValue* value = args->current();
8642 if (!validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode))
8645 double amount = value->fValue;
8647 // Saturate and Contrast allow values over 100%.
8648 if (filterType != CSSFilterValue::SaturateFilterOperation
8649 && filterType != CSSFilterValue::ContrastFilterOperation) {
8650 double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
8651 if (amount > maxAllowed)
8655 filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
8659 case CSSFilterValue::BrightnessFilterOperation: {
8660 // One optional argument, if missing use 100%.
8661 if (args->size() > 1)
8665 CSSParserValue* value = args->current();
8666 if (!validUnit(value, FNumber | FPercent, HTMLStandardMode))
8669 filterValue->append(cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
8673 case CSSFilterValue::HueRotateFilterOperation: {
8674 // hue-rotate() takes one optional angle.
8675 if (args->size() > 1)
8679 CSSParserValue* argument = args->current();
8680 if (!validUnit(argument, FAngle, HTMLStandardMode))
8683 filterValue->append(createPrimitiveNumericValue(argument));
8687 case CSSFilterValue::BlurFilterOperation: {
8688 // Blur takes a single length. Zero parameters are allowed.
8689 if (args->size() > 1)
8693 CSSParserValue* argument = args->current();
8694 if (!validUnit(argument, FLength | FNonNeg, HTMLStandardMode))
8697 filterValue->append(createPrimitiveNumericValue(argument));
8701 case CSSFilterValue::DropShadowFilterOperation: {
8702 // drop-shadow() takes a single shadow.
8703 RefPtrWillBeRawPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter);
8704 if (!shadowValueList || shadowValueList->length() != 1)
8707 filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0));
8711 ASSERT_NOT_REACHED();
8713 return filterValue.release();
8716 PassRefPtrWillBeRawPtr<CSSValueList> BisonCSSParser::parseFilter()
8721 // The filter is a list of functional primitives that specify individual operations.
8722 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8723 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
8724 if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function))
8727 CSSFilterValue::FilterOperationType filterType = CSSFilterValue::UnknownFilterOperation;
8729 // See if the specified primitive is one we understand.
8730 if (value->unit == CSSPrimitiveValue::CSS_URI) {
8731 RefPtrWillBeRawPtr<CSSFilterValue> referenceFilterValue = CSSFilterValue::create(CSSFilterValue::ReferenceFilterOperation);
8732 list->append(referenceFilterValue);
8733 referenceFilterValue->append(CSSSVGDocumentValue::create(value->string));
8735 const CSSParserString name = value->function->name;
8736 unsigned maximumArgumentCount = 1;
8738 filterInfoForName(name, filterType, maximumArgumentCount);
8740 if (filterType == CSSFilterValue::UnknownFilterOperation)
8743 CSSParserValueList* args = value->function->args.get();
8747 RefPtrWillBeRawPtr<CSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType);
8751 list->append(filterValue);
8755 return list.release();
8758 bool BisonCSSParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
8763 if (propId == CSSPropertyWebkitTransformOrigin) {
8764 propId1 = CSSPropertyWebkitTransformOriginX;
8765 propId2 = CSSPropertyWebkitTransformOriginY;
8766 propId3 = CSSPropertyWebkitTransformOriginZ;
8770 case CSSPropertyWebkitTransformOrigin:
8771 if (!parseTransformOriginShorthand(value, value2, value3))
8773 // parseTransformOriginShorthand advances the m_valueList pointer
8775 case CSSPropertyWebkitTransformOriginX: {
8776 value = parseFillPositionX(m_valueList.get());
8778 m_valueList->next();
8781 case CSSPropertyWebkitTransformOriginY: {
8782 value = parseFillPositionY(m_valueList.get());
8784 m_valueList->next();
8787 case CSSPropertyWebkitTransformOriginZ: {
8788 if (validUnit(m_valueList->current(), FLength))
8789 value = createPrimitiveNumericValue(m_valueList->current());
8791 m_valueList->next();
8795 ASSERT_NOT_REACHED();
8802 bool BisonCSSParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2)
8806 if (propId == CSSPropertyWebkitPerspectiveOrigin) {
8807 propId1 = CSSPropertyWebkitPerspectiveOriginX;
8808 propId2 = CSSPropertyWebkitPerspectiveOriginY;
8812 case CSSPropertyWebkitPerspectiveOrigin:
8813 if (m_valueList->size() > 2)
8815 parse2ValuesFillPosition(m_valueList.get(), value, value2);
8817 case CSSPropertyWebkitPerspectiveOriginX: {
8818 value = parseFillPositionX(m_valueList.get());
8820 m_valueList->next();
8823 case CSSPropertyWebkitPerspectiveOriginY: {
8824 value = parseFillPositionY(m_valueList.get());
8826 m_valueList->next();
8830 ASSERT_NOT_REACHED();
8837 bool BisonCSSParser::parseTouchAction(bool important)
8839 if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
8842 CSSParserValue* value = m_valueList->current();
8843 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8844 if (m_valueList->size() == 1 && value && (value->id == CSSValueAuto || value->id == CSSValueNone)) {
8845 list->append(cssValuePool().createIdentifierValue(value->id));
8846 addProperty(CSSPropertyTouchAction, list.release(), important);
8847 m_valueList->next();
8851 bool isValid = true;
8852 while (isValid && value) {
8853 switch (value->id) {
8855 case CSSValuePanY: {
8856 RefPtr<CSSValue> panValue = cssValuePool().createIdentifierValue(value->id);
8857 if (list->hasValue(panValue.get())) {
8861 list->append(panValue.release());
8869 value = m_valueList->next();
8872 if (list->length() && isValid) {
8873 addProperty(CSSPropertyTouchAction, list.release(), important);
8880 void BisonCSSParser::addTextDecorationProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important)
8882 // The text-decoration-line property takes priority over text-decoration, unless the latter has important priority set.
8883 if (propId == CSSPropertyTextDecoration && !important && !inShorthand()) {
8884 for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
8885 if (m_parsedProperties[i].id() == CSSPropertyTextDecorationLine)
8889 addProperty(propId, value, important);
8892 bool BisonCSSParser::parseTextDecoration(CSSPropertyID propId, bool important)
8894 if (propId == CSSPropertyTextDecorationLine
8895 && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
8898 CSSParserValue* value = m_valueList->current();
8899 if (value && value->id == CSSValueNone) {
8900 addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
8901 m_valueList->next();
8905 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8906 bool isValid = true;
8907 while (isValid && value) {
8908 switch (value->id) {
8909 case CSSValueUnderline:
8910 case CSSValueOverline:
8911 case CSSValueLineThrough:
8913 list->append(cssValuePool().createIdentifierValue(value->id));
8920 value = m_valueList->next();
8923 // Values are either valid or in shorthand scope.
8924 if (list->length() && (isValid || inShorthand())) {
8925 addTextDecorationProperty(propId, list.release(), important);
8932 bool BisonCSSParser::parseTextUnderlinePosition(bool important)
8934 // The text-underline-position property has syntax "auto | [ under || [ left | right ] ]".
8935 // However, values 'left' and 'right' are not implemented yet, so we will parse syntax
8936 // "auto | under" for now.
8937 CSSParserValue* value = m_valueList->current();
8938 switch (value->id) {
8941 if (m_valueList->next())
8943 addProperty(CSSPropertyTextUnderlinePosition, cssValuePool().createIdentifierValue(value->id), important);
8950 bool BisonCSSParser::parseTextEmphasisStyle(bool important)
8952 unsigned valueListSize = m_valueList->size();
8954 RefPtrWillBeRawPtr<CSSPrimitiveValue> fill;
8955 RefPtrWillBeRawPtr<CSSPrimitiveValue> shape;
8957 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
8958 if (value->unit == CSSPrimitiveValue::CSS_STRING) {
8959 if (fill || shape || (valueListSize != 1 && !inShorthand()))
8961 addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important);
8962 m_valueList->next();
8966 if (value->id == CSSValueNone) {
8967 if (fill || shape || (valueListSize != 1 && !inShorthand()))
8969 addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important);
8970 m_valueList->next();
8974 if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
8977 fill = cssValuePool().createIdentifierValue(value->id);
8978 } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
8981 shape = cssValuePool().createIdentifierValue(value->id);
8982 } else if (!inShorthand())
8988 if (fill && shape) {
8989 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
8990 parsedValues->append(fill.release());
8991 parsedValues->append(shape.release());
8992 addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
8996 addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
9000 addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
9007 PassRefPtr<CSSValue> BisonCSSParser::parseTextIndent()
9009 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9011 // <length> | <percentage> | inherit
9012 if (m_valueList->size() == 1) {
9013 CSSParserValue* value = m_valueList->current();
9014 if (!value->id && validUnit(value, FLength | FPercent)) {
9015 list->append(createPrimitiveNumericValue(value));
9016 m_valueList->next();
9017 return list.release();
9021 if (!RuntimeEnabledFeatures::css3TextEnabled())
9024 // The case where text-indent has only <length>(or <percentage>) value
9025 // is handled above if statement even though css3TextEnabled() returns true.
9027 // [ [ <length> | <percentage> ] && each-line ] | inherit
9028 if (m_valueList->size() != 2)
9031 CSSParserValue* firstValue = m_valueList->current();
9032 CSSParserValue* secondValue = m_valueList->next();
9033 CSSParserValue* lengthOrPercentageValue = 0;
9035 // [ <length> | <percentage> ] each-line
9036 if (validUnit(firstValue, FLength | FPercent) && secondValue->id == CSSValueEachLine)
9037 lengthOrPercentageValue = firstValue;
9038 // each-line [ <length> | <percentage> ]
9039 else if (firstValue->id == CSSValueEachLine && validUnit(secondValue, FLength | FPercent))
9040 lengthOrPercentageValue = secondValue;
9042 if (lengthOrPercentageValue) {
9043 list->append(createPrimitiveNumericValue(lengthOrPercentageValue));
9044 list->append(cssValuePool().createIdentifierValue(CSSValueEachLine));
9045 m_valueList->next();
9046 return list.release();
9052 bool BisonCSSParser::parseLineBoxContain(bool important)
9054 LineBoxContain lineBoxContain = LineBoxContainNone;
9056 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9057 if (value->id == CSSValueBlock) {
9058 if (lineBoxContain & LineBoxContainBlock)
9060 lineBoxContain |= LineBoxContainBlock;
9061 } else if (value->id == CSSValueInline) {
9062 if (lineBoxContain & LineBoxContainInline)
9064 lineBoxContain |= LineBoxContainInline;
9065 } else if (value->id == CSSValueFont) {
9066 if (lineBoxContain & LineBoxContainFont)
9068 lineBoxContain |= LineBoxContainFont;
9069 } else if (value->id == CSSValueGlyphs) {
9070 if (lineBoxContain & LineBoxContainGlyphs)
9072 lineBoxContain |= LineBoxContainGlyphs;
9073 } else if (value->id == CSSValueReplaced) {
9074 if (lineBoxContain & LineBoxContainReplaced)
9076 lineBoxContain |= LineBoxContainReplaced;
9077 } else if (value->id == CSSValueInlineBox) {
9078 if (lineBoxContain & LineBoxContainInlineBox)
9080 lineBoxContain |= LineBoxContainInlineBox;
9085 if (!lineBoxContain)
9088 addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
9092 bool BisonCSSParser::parseFontFeatureTag(CSSValueList* settings)
9094 // Feature tag name consists of 4-letter characters.
9095 static const unsigned tagNameLength = 4;
9097 CSSParserValue* value = m_valueList->current();
9098 // Feature tag name comes first
9099 if (value->unit != CSSPrimitiveValue::CSS_STRING)
9101 if (value->string.length() != tagNameLength)
9103 for (unsigned i = 0; i < tagNameLength; ++i) {
9104 // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
9105 UChar character = value->string[i];
9106 if (character < 0x20 || character > 0x7E)
9110 AtomicString tag = value->string;
9112 // Feature tag values could follow: <integer> | on | off
9113 value = m_valueList->next();
9115 if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
9116 tagValue = clampToInteger(value->fValue);
9119 m_valueList->next();
9120 } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
9121 tagValue = value->id == CSSValueOn;
9122 m_valueList->next();
9125 settings->append(CSSFontFeatureValue::create(tag, tagValue));
9129 bool BisonCSSParser::parseFontFeatureSettings(bool important)
9131 if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) {
9132 RefPtrWillBeRawPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal);
9133 m_valueList->next();
9134 addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
9138 RefPtrWillBeRawPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
9139 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9140 if (!parseFontFeatureTag(settings.get()))
9143 // If the list isn't parsed fully, the current value should be comma.
9144 value = m_valueList->current();
9145 if (value && !isComma(value))
9148 if (settings->length()) {
9149 addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important);
9155 bool BisonCSSParser::parseFontVariantLigatures(bool important)
9157 RefPtrWillBeRawPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
9158 bool sawCommonLigaturesValue = false;
9159 bool sawDiscretionaryLigaturesValue = false;
9160 bool sawHistoricalLigaturesValue = false;
9162 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9163 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
9166 switch (value->id) {
9167 case CSSValueNoCommonLigatures:
9168 case CSSValueCommonLigatures:
9169 if (sawCommonLigaturesValue)
9171 sawCommonLigaturesValue = true;
9172 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9174 case CSSValueNoDiscretionaryLigatures:
9175 case CSSValueDiscretionaryLigatures:
9176 if (sawDiscretionaryLigaturesValue)
9178 sawDiscretionaryLigaturesValue = true;
9179 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9181 case CSSValueNoHistoricalLigatures:
9182 case CSSValueHistoricalLigatures:
9183 if (sawHistoricalLigaturesValue)
9185 sawHistoricalLigaturesValue = true;
9186 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9193 if (!ligatureValues->length())
9196 addProperty(CSSPropertyFontVariantLigatures, ligatureValues.release(), important);
9200 bool BisonCSSParser::parseCalculation(CSSParserValue* value, ValueRange range)
9202 ASSERT(isCalculation(value));
9204 CSSParserValueList* args = value->function->args.get();
9205 if (!args || !args->size())
9208 ASSERT(!m_parsedCalculation);
9209 m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
9211 if (!m_parsedCalculation)
9219 void BisonCSSParser::ensureLineEndings()
9222 m_lineEndings = lineEndings(*m_source);
9225 CSSParserSelector* BisonCSSParser::createFloatingSelectorWithTagName(const QualifiedName& tagQName)
9227 CSSParserSelector* selector = new CSSParserSelector(tagQName);
9228 m_floatingSelectors.append(selector);
9232 CSSParserSelector* BisonCSSParser::createFloatingSelector()
9234 CSSParserSelector* selector = new CSSParserSelector;
9235 m_floatingSelectors.append(selector);
9239 PassOwnPtr<CSSParserSelector> BisonCSSParser::sinkFloatingSelector(CSSParserSelector* selector)
9242 size_t index = m_floatingSelectors.reverseFind(selector);
9243 ASSERT(index != kNotFound);
9244 m_floatingSelectors.remove(index);
9246 return adoptPtr(selector);
9249 Vector<OwnPtr<CSSParserSelector> >* BisonCSSParser::createFloatingSelectorVector()
9251 Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >;
9252 m_floatingSelectorVectors.append(selectorVector);
9253 return selectorVector;
9256 PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > BisonCSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector)
9258 if (selectorVector) {
9259 size_t index = m_floatingSelectorVectors.reverseFind(selectorVector);
9260 ASSERT(index != kNotFound);
9261 m_floatingSelectorVectors.remove(index);
9263 return adoptPtr(selectorVector);
9266 CSSParserValueList* BisonCSSParser::createFloatingValueList()
9268 CSSParserValueList* list = new CSSParserValueList;
9269 m_floatingValueLists.append(list);
9273 PassOwnPtr<CSSParserValueList> BisonCSSParser::sinkFloatingValueList(CSSParserValueList* list)
9276 size_t index = m_floatingValueLists.reverseFind(list);
9277 ASSERT(index != kNotFound);
9278 m_floatingValueLists.remove(index);
9280 return adoptPtr(list);
9283 CSSParserFunction* BisonCSSParser::createFloatingFunction()
9285 CSSParserFunction* function = new CSSParserFunction;
9286 m_floatingFunctions.append(function);
9290 CSSParserFunction* BisonCSSParser::createFloatingFunction(const CSSParserString& name, PassOwnPtr<CSSParserValueList> args)
9292 CSSParserFunction* function = createFloatingFunction();
9293 function->name = name;
9294 function->args = args;
9298 PassOwnPtr<CSSParserFunction> BisonCSSParser::sinkFloatingFunction(CSSParserFunction* function)
9301 size_t index = m_floatingFunctions.reverseFind(function);
9302 ASSERT(index != kNotFound);
9303 m_floatingFunctions.remove(index);
9305 return adoptPtr(function);
9308 CSSParserValue& BisonCSSParser::sinkFloatingValue(CSSParserValue& value)
9310 if (value.unit == CSSParserValue::Function) {
9311 size_t index = m_floatingFunctions.reverseFind(value.function);
9312 ASSERT(index != kNotFound);
9313 m_floatingFunctions.remove(index);
9318 MediaQueryExp* BisonCSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
9320 m_floatingMediaQueryExp = MediaQueryExp::create(mediaFeature, values);
9321 return m_floatingMediaQueryExp.get();
9324 PassOwnPtr<MediaQueryExp> BisonCSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression)
9326 ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp);
9327 return m_floatingMediaQueryExp.release();
9330 Vector<OwnPtr<MediaQueryExp> >* BisonCSSParser::createFloatingMediaQueryExpList()
9332 m_floatingMediaQueryExpList = adoptPtr(new Vector<OwnPtr<MediaQueryExp> >);
9333 return m_floatingMediaQueryExpList.get();
9336 PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > BisonCSSParser::sinkFloatingMediaQueryExpList(Vector<OwnPtr<MediaQueryExp> >* list)
9338 ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList);
9339 return m_floatingMediaQueryExpList.release();
9342 MediaQuery* BisonCSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const AtomicString& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
9344 m_floatingMediaQuery = adoptPtr(new MediaQuery(restrictor, mediaType, expressions));
9345 return m_floatingMediaQuery.get();
9348 MediaQuery* BisonCSSParser::createFloatingMediaQuery(PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
9350 return createFloatingMediaQuery(MediaQuery::None, AtomicString("all", AtomicString::ConstructFromLiteral), expressions);
9353 MediaQuery* BisonCSSParser::createFloatingNotAllQuery()
9355 return createFloatingMediaQuery(MediaQuery::Not, AtomicString("all", AtomicString::ConstructFromLiteral), sinkFloatingMediaQueryExpList(createFloatingMediaQueryExpList()));
9358 PassOwnPtr<MediaQuery> BisonCSSParser::sinkFloatingMediaQuery(MediaQuery* query)
9360 ASSERT_UNUSED(query, query == m_floatingMediaQuery);
9361 return m_floatingMediaQuery.release();
9364 Vector<RefPtr<StyleKeyframe> >* BisonCSSParser::createFloatingKeyframeVector()
9366 m_floatingKeyframeVector = adoptPtr(new Vector<RefPtr<StyleKeyframe> >());
9367 return m_floatingKeyframeVector.get();
9370 PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > BisonCSSParser::sinkFloatingKeyframeVector(Vector<RefPtr<StyleKeyframe> >* keyframeVector)
9372 ASSERT_UNUSED(keyframeVector, m_floatingKeyframeVector == keyframeVector);
9373 return m_floatingKeyframeVector.release();
9376 MediaQuerySet* BisonCSSParser::createMediaQuerySet()
9378 RefPtr<MediaQuerySet> queries = MediaQuerySet::create();
9379 MediaQuerySet* result = queries.get();
9380 m_parsedMediaQuerySets.append(queries.release());
9384 StyleRuleBase* BisonCSSParser::createImportRule(const CSSParserString& url, MediaQuerySet* media)
9386 if (!media || !m_allowImportRules)
9388 RefPtr<StyleRuleImport> rule = StyleRuleImport::create(url, media);
9389 StyleRuleImport* result = rule.get();
9390 m_parsedRules.append(rule.release());
9394 StyleRuleBase* BisonCSSParser::createMediaRule(MediaQuerySet* media, RuleList* rules)
9396 m_allowImportRules = m_allowNamespaceDeclarations = false;
9397 RefPtr<StyleRuleMedia> rule;
9399 rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), *rules);
9401 RuleList emptyRules;
9402 rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), emptyRules);
9404 StyleRuleMedia* result = rule.get();
9405 m_parsedRules.append(rule.release());
9409 StyleRuleBase* BisonCSSParser::createSupportsRule(bool conditionIsSupported, RuleList* rules)
9411 m_allowImportRules = m_allowNamespaceDeclarations = false;
9413 RefPtr<CSSRuleSourceData> data = popSupportsRuleData();
9414 RefPtr<StyleRuleSupports> rule;
9415 String conditionText;
9416 unsigned conditionOffset = data->ruleHeaderRange.start + 9;
9417 unsigned conditionLength = data->ruleHeaderRange.length() - 9;
9419 if (m_tokenizer.is8BitSource())
9420 conditionText = String(m_tokenizer.m_dataStart8.get() + conditionOffset, conditionLength).stripWhiteSpace();
9422 conditionText = String(m_tokenizer.m_dataStart16.get() + conditionOffset, conditionLength).stripWhiteSpace();
9425 rule = StyleRuleSupports::create(conditionText, conditionIsSupported, *rules);
9427 RuleList emptyRules;
9428 rule = StyleRuleSupports::create(conditionText, conditionIsSupported, emptyRules);
9431 StyleRuleSupports* result = rule.get();
9432 m_parsedRules.append(rule.release());
9437 void BisonCSSParser::markSupportsRuleHeaderStart()
9439 if (!m_supportsRuleDataStack)
9440 m_supportsRuleDataStack = adoptPtr(new RuleSourceDataList());
9442 RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(CSSRuleSourceData::SUPPORTS_RULE);
9443 data->ruleHeaderRange.start = m_tokenizer.tokenStartOffset();
9444 m_supportsRuleDataStack->append(data);
9447 void BisonCSSParser::markSupportsRuleHeaderEnd()
9449 ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
9451 if (m_tokenizer.is8BitSource())
9452 m_supportsRuleDataStack->last()->ruleHeaderRange.end = m_tokenizer.tokenStart<LChar>() - m_tokenizer.m_dataStart8.get();
9454 m_supportsRuleDataStack->last()->ruleHeaderRange.end = m_tokenizer.tokenStart<UChar>() - m_tokenizer.m_dataStart16.get();
9457 PassRefPtr<CSSRuleSourceData> BisonCSSParser::popSupportsRuleData()
9459 ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
9460 RefPtr<CSSRuleSourceData> data = m_supportsRuleDataStack->last();
9461 m_supportsRuleDataStack->removeLast();
9462 return data.release();
9465 BisonCSSParser::RuleList* BisonCSSParser::createRuleList()
9467 OwnPtr<RuleList> list = adoptPtr(new RuleList);
9468 RuleList* listPtr = list.get();
9470 m_parsedRuleLists.append(list.release());
9474 BisonCSSParser::RuleList* BisonCSSParser::appendRule(RuleList* ruleList, StyleRuleBase* rule)
9478 ruleList = createRuleList();
9479 ruleList->append(rule);
9484 template <typename CharacterType>
9485 ALWAYS_INLINE static void makeLower(const CharacterType* input, CharacterType* output, unsigned length)
9487 // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
9488 // that can potentially change the length of the string rather than the character
9489 // by character kind. If we don't need Unicode lowercasing, it would be good to
9490 // simplify this function.
9492 if (charactersAreAllASCII(input, length)) {
9493 // Fast case for all-ASCII.
9494 for (unsigned i = 0; i < length; i++)
9495 output[i] = toASCIILower(input[i]);
9497 for (unsigned i = 0; i < length; i++)
9498 output[i] = Unicode::toLower(input[i]);
9502 void BisonCSSParser::tokenToLowerCase(const CSSParserString& token)
9504 size_t length = token.length();
9505 if (m_tokenizer.is8BitSource()) {
9506 size_t offset = token.characters8() - m_tokenizer.m_dataStart8.get();
9507 makeLower(token.characters8(), m_tokenizer.m_dataStart8.get() + offset, length);
9509 size_t offset = token.characters16() - m_tokenizer.m_dataStart16.get();
9510 makeLower(token.characters16(), m_tokenizer.m_dataStart16.get() + offset, length);
9514 void BisonCSSParser::endInvalidRuleHeader()
9516 if (m_ruleHeaderType == CSSRuleSourceData::UNKNOWN_RULE)
9519 CSSParserLocation location;
9520 location.lineNumber = m_tokenizer.m_lineNumber;
9521 location.offset = m_ruleHeaderStartOffset;
9522 if (m_tokenizer.is8BitSource())
9523 location.token.init(m_tokenizer.m_dataStart8.get() + m_ruleHeaderStartOffset, 0);
9525 location.token.init(m_tokenizer.m_dataStart16.get() + m_ruleHeaderStartOffset, 0);
9527 reportError(location, m_ruleHeaderType == CSSRuleSourceData::STYLE_RULE ? InvalidSelectorCSSError : InvalidRuleCSSError);
9532 void BisonCSSParser::reportError(const CSSParserLocation&, CSSParserError)
9534 // FIXME: error reporting temporatily disabled.
9537 bool BisonCSSParser::isLoggingErrors()
9539 return m_logErrors && !m_ignoreErrors;
9542 void BisonCSSParser::logError(const String& message, const CSSParserLocation& location)
9544 unsigned lineNumberInStyleSheet;
9545 unsigned columnNumber = 0;
9546 if (InspectorInstrumentation::hasFrontends()) {
9547 ensureLineEndings();
9548 TextPosition tokenPosition = TextPosition::fromOffsetAndLineEndings(location.offset, *m_lineEndings);
9549 lineNumberInStyleSheet = tokenPosition.m_line.zeroBasedInt();
9550 columnNumber = (lineNumberInStyleSheet ? 0 : m_startPosition.m_column.zeroBasedInt()) + tokenPosition.m_column.zeroBasedInt();
9552 lineNumberInStyleSheet = location.lineNumber;
9554 PageConsole& console = m_styleSheet->singleOwnerDocument()->frameHost()->console();
9555 console.addMessage(CSSMessageSource, WarningMessageLevel, message, m_styleSheet->baseURL().string(), lineNumberInStyleSheet + m_startPosition.m_line.zeroBasedInt() + 1, columnNumber + 1);
9558 StyleRuleKeyframes* BisonCSSParser::createKeyframesRule(const String& name, PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > popKeyframes, bool isPrefixed)
9560 OwnPtr<Vector<RefPtr<StyleKeyframe> > > keyframes = popKeyframes;
9561 m_allowImportRules = m_allowNamespaceDeclarations = false;
9562 RefPtr<StyleRuleKeyframes> rule = StyleRuleKeyframes::create();
9563 for (size_t i = 0; i < keyframes->size(); ++i)
9564 rule->parserAppendKeyframe(keyframes->at(i));
9565 rule->setName(name);
9566 rule->setVendorPrefixed(isPrefixed);
9567 StyleRuleKeyframes* rulePtr = rule.get();
9568 m_parsedRules.append(rule.release());
9572 StyleRuleBase* BisonCSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors)
9574 StyleRule* result = 0;
9576 m_allowImportRules = m_allowNamespaceDeclarations = false;
9577 RefPtr<StyleRule> rule = StyleRule::create();
9578 rule->parserAdoptSelectorVector(*selectors);
9579 if (m_hasFontFaceOnlyValues)
9580 deleteFontFaceOnlyValues();
9581 rule->setProperties(createStylePropertySet());
9582 result = rule.get();
9583 m_parsedRules.append(rule.release());
9589 StyleRuleBase* BisonCSSParser::createFontFaceRule()
9591 m_allowImportRules = m_allowNamespaceDeclarations = false;
9592 for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
9593 CSSProperty& property = m_parsedProperties[i];
9594 if (property.id() == CSSPropertyFontVariant && property.value()->isPrimitiveValue())
9595 property.wrapValueInCommaSeparatedList();
9596 else if (property.id() == CSSPropertyFontFamily && (!property.value()->isValueList() || toCSSValueList(property.value())->length() != 1)) {
9597 // Unlike font-family property, font-family descriptor in @font-face rule
9598 // has to be a value list with exactly one family name. It cannot have a
9599 // have 'initial' value and cannot 'inherit' from parent.
9600 // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
9605 RefPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create();
9606 rule->setProperties(createStylePropertySet());
9608 StyleRuleFontFace* result = rule.get();
9609 m_parsedRules.append(rule.release());
9611 m_styleSheet->setHasFontFaceRule(true);
9615 void BisonCSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
9617 if (!m_styleSheet || !m_allowNamespaceDeclarations)
9619 m_allowImportRules = false;
9620 m_styleSheet->parserAddNamespace(prefix, uri);
9621 if (prefix.isEmpty() && !uri.isNull())
9622 m_defaultNamespace = uri;
9625 QualifiedName BisonCSSParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName)
9628 return QualifiedName(prefix, localName, m_defaultNamespace);
9629 return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix));
9632 CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector* specifiers)
9634 if (m_defaultNamespace != starAtom || specifiers->needsCrossingTreeScopeBoundary())
9635 return rewriteSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true);
9636 if (CSSParserSelector* distributedPseudoElementSelector = specifiers->findDistributedPseudoElementSelector()) {
9637 specifiers->prependTagSelector(QualifiedName(nullAtom, starAtom, m_defaultNamespace), /*tagIsForNamespaceRule*/true);
9638 return rewriteSpecifiersForShadowDistributed(specifiers, distributedPseudoElementSelector);
9643 CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
9645 AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
9646 QualifiedName tag(namespacePrefix, elementName, determinedNamespace);
9648 if (CSSParserSelector* distributedPseudoElementSelector = specifiers->findDistributedPseudoElementSelector()) {
9649 specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
9650 return rewriteSpecifiersForShadowDistributed(specifiers, distributedPseudoElementSelector);
9653 if (specifiers->needsCrossingTreeScopeBoundary())
9654 return rewriteSpecifiersWithElementNameForCustomPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
9656 if (specifiers->isContentPseudoElement())
9657 return rewriteSpecifiersWithElementNameForContentPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
9659 if (tag == anyQName())
9661 if (!(specifiers->pseudoType() == CSSSelector::PseudoCue))
9662 specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
9666 CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementNameForCustomPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
9668 if (m_context.useCounter() && specifiers->pseudoType() == CSSSelector::PseudoUserAgentCustomElement)
9669 m_context.useCounter()->count(UseCounter::CSSPseudoElementUserAgentCustomPseudo);
9671 CSSParserSelector* lastShadowPseudo = specifiers;
9672 CSSParserSelector* history = specifiers;
9673 while (history->tagHistory()) {
9674 history = history->tagHistory();
9675 if (history->needsCrossingTreeScopeBoundary() || history->hasShadowPseudo())
9676 lastShadowPseudo = history;
9679 if (lastShadowPseudo->tagHistory()) {
9680 if (tag != anyQName())
9681 lastShadowPseudo->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
9685 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
9686 // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
9687 OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
9688 lastShadowPseudo->setTagHistory(elementNameSelector.release());
9689 lastShadowPseudo->setRelation(CSSSelector::ShadowPseudo);
9693 CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementNameForContentPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
9695 CSSParserSelector* last = specifiers;
9696 CSSParserSelector* history = specifiers;
9697 while (history->tagHistory()) {
9698 history = history->tagHistory();
9699 if (history->isContentPseudoElement() || history->relationIsAffectedByPseudoContent())
9703 if (last->tagHistory()) {
9704 if (tag != anyQName())
9705 last->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
9709 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
9710 // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
9711 OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
9712 last->setTagHistory(elementNameSelector.release());
9713 last->setRelation(CSSSelector::SubSelector);
9717 CSSParserSelector* BisonCSSParser::rewriteSpecifiersForShadowDistributed(CSSParserSelector* specifiers, CSSParserSelector* distributedPseudoElementSelector)
9719 if (m_context.useCounter())
9720 m_context.useCounter()->count(UseCounter::CSSPseudoElementPrefixedDistributed);
9721 CSSParserSelector* argumentSelector = distributedPseudoElementSelector->functionArgumentSelector();
9722 ASSERT(argumentSelector);
9723 ASSERT(!specifiers->isDistributedPseudoElement());
9724 for (CSSParserSelector* end = specifiers; end->tagHistory(); end = end->tagHistory()) {
9725 if (end->tagHistory()->isDistributedPseudoElement()) {
9726 end->clearTagHistory();
9730 CSSParserSelector* end = argumentSelector;
9731 while (end->tagHistory())
9732 end = end->tagHistory();
9734 switch (end->relation()) {
9735 case CSSSelector::Child:
9736 case CSSSelector::Descendant:
9737 end->setTagHistory(sinkFloatingSelector(specifiers));
9738 end->setRelationIsAffectedByPseudoContent();
9739 return argumentSelector;
9745 CSSParserSelector* BisonCSSParser::rewriteSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier)
9747 if (newSpecifier->needsCrossingTreeScopeBoundary()) {
9748 // Unknown pseudo element always goes at the top of selector chain.
9749 newSpecifier->appendTagHistory(CSSSelector::ShadowPseudo, sinkFloatingSelector(specifiers));
9750 return newSpecifier;
9752 if (newSpecifier->isContentPseudoElement()) {
9753 newSpecifier->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(specifiers));
9754 return newSpecifier;
9756 if (specifiers->needsCrossingTreeScopeBoundary()) {
9757 // Specifiers for unknown pseudo element go right behind it in the chain.
9758 specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::ShadowPseudo);
9761 if (specifiers->isContentPseudoElement()) {
9762 specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::SubSelector);
9765 specifiers->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier));
9769 StyleRuleBase* BisonCSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector)
9771 // FIXME: Margin at-rules are ignored.
9772 m_allowImportRules = m_allowNamespaceDeclarations = false;
9773 StyleRulePage* pageRule = 0;
9775 RefPtr<StyleRulePage> rule = StyleRulePage::create();
9776 Vector<OwnPtr<CSSParserSelector> > selectorVector;
9777 selectorVector.append(pageSelector);
9778 rule->parserAdoptSelectorVector(selectorVector);
9779 rule->setProperties(createStylePropertySet());
9780 pageRule = rule.get();
9781 m_parsedRules.append(rule.release());
9787 StyleRuleBase* BisonCSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
9789 // FIXME: Implement margin at-rule here, using:
9790 // - marginBox: margin box
9791 // - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_parsedProperties.size()] are for this at-rule.
9792 // 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.
9794 endDeclarationsForMarginBox();
9795 return 0; // until this method is implemented.
9798 void BisonCSSParser::startDeclarationsForMarginBox()
9800 m_numParsedPropertiesBeforeMarginBox = m_parsedProperties.size();
9803 void BisonCSSParser::endDeclarationsForMarginBox()
9805 rollbackLastProperties(m_parsedProperties.size() - m_numParsedPropertiesBeforeMarginBox);
9806 m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
9809 void BisonCSSParser::deleteFontFaceOnlyValues()
9811 ASSERT(m_hasFontFaceOnlyValues);
9812 for (unsigned i = 0; i < m_parsedProperties.size();) {
9813 CSSProperty& property = m_parsedProperties[i];
9814 if (property.id() == CSSPropertyFontVariant && property.value()->isValueList()) {
9815 m_parsedProperties.remove(i);
9822 StyleKeyframe* BisonCSSParser::createKeyframe(CSSParserValueList* keys)
9824 OwnPtr<Vector<double> > keyVector = StyleKeyframe::createKeyList(keys);
9825 if (keyVector->isEmpty())
9828 RefPtr<StyleKeyframe> keyframe = StyleKeyframe::create();
9829 keyframe->setKeys(keyVector.release());
9830 keyframe->setProperties(createStylePropertySet());
9834 StyleKeyframe* keyframePtr = keyframe.get();
9835 m_parsedKeyframes.append(keyframe.release());
9839 void BisonCSSParser::invalidBlockHit()
9841 if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
9842 m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
9845 void BisonCSSParser::startRule()
9850 ASSERT(m_ruleHasHeader);
9851 m_ruleHasHeader = false;
9854 void BisonCSSParser::endRule(bool valid)
9859 if (m_ruleHasHeader)
9860 m_observer->endRuleBody(m_tokenizer.safeUserStringTokenOffset(), !valid);
9861 m_ruleHasHeader = true;
9864 void BisonCSSParser::startRuleHeader(CSSRuleSourceData::Type ruleType)
9866 resumeErrorLogging();
9867 m_ruleHeaderType = ruleType;
9868 m_ruleHeaderStartOffset = m_tokenizer.safeUserStringTokenOffset();
9869 m_ruleHeaderStartLineNumber = m_tokenizer.m_tokenStartLineNumber;
9871 ASSERT(!m_ruleHasHeader);
9872 m_observer->startRuleHeader(ruleType, m_ruleHeaderStartOffset);
9873 m_ruleHasHeader = true;
9877 void BisonCSSParser::endRuleHeader()
9879 ASSERT(m_ruleHeaderType != CSSRuleSourceData::UNKNOWN_RULE);
9880 m_ruleHeaderType = CSSRuleSourceData::UNKNOWN_RULE;
9882 ASSERT(m_ruleHasHeader);
9883 m_observer->endRuleHeader(m_tokenizer.safeUserStringTokenOffset());
9887 void BisonCSSParser::startSelector()
9890 m_observer->startSelector(m_tokenizer.safeUserStringTokenOffset());
9893 void BisonCSSParser::endSelector()
9896 m_observer->endSelector(m_tokenizer.safeUserStringTokenOffset());
9899 void BisonCSSParser::startRuleBody()
9902 m_observer->startRuleBody(m_tokenizer.safeUserStringTokenOffset());
9905 void BisonCSSParser::startProperty()
9907 resumeErrorLogging();
9909 m_observer->startProperty(m_tokenizer.safeUserStringTokenOffset());
9912 void BisonCSSParser::endProperty(bool isImportantFound, bool isPropertyParsed, CSSParserError errorType)
9914 m_id = CSSPropertyInvalid;
9916 m_observer->endProperty(isImportantFound, isPropertyParsed, m_tokenizer.safeUserStringTokenOffset(), errorType);
9919 void BisonCSSParser::startEndUnknownRule()
9922 m_observer->startEndUnknownRule();
9925 StyleRuleBase* BisonCSSParser::createViewportRule()
9927 // Allow @viewport rules from UA stylesheets even if the feature is disabled.
9928 if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode()))
9931 m_allowImportRules = m_allowNamespaceDeclarations = false;
9933 RefPtr<StyleRuleViewport> rule = StyleRuleViewport::create();
9935 rule->setProperties(createStylePropertySet());
9938 StyleRuleViewport* result = rule.get();
9939 m_parsedRules.append(rule.release());
9944 bool BisonCSSParser::parseViewportProperty(CSSPropertyID propId, bool important)
9946 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
9948 CSSParserValue* value = m_valueList->current();
9952 CSSValueID id = value->id;
9953 bool validPrimitive = false;
9956 case CSSPropertyMinWidth: // auto | extend-to-zoom | <length> | <percentage>
9957 case CSSPropertyMaxWidth:
9958 case CSSPropertyMinHeight:
9959 case CSSPropertyMaxHeight:
9960 if (id == CSSValueAuto || id == CSSValueInternalExtendToZoom)
9961 validPrimitive = true;
9963 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
9965 case CSSPropertyWidth: // shorthand
9966 return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMaxWidth, important);
9967 case CSSPropertyHeight:
9968 return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyMaxHeight, important);
9969 case CSSPropertyMinZoom: // auto | <number> | <percentage>
9970 case CSSPropertyMaxZoom:
9971 case CSSPropertyZoom:
9972 if (id == CSSValueAuto)
9973 validPrimitive = true;
9975 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg));
9977 case CSSPropertyUserZoom: // zoom | fixed
9978 if (id == CSSValueZoom || id == CSSValueFixed)
9979 validPrimitive = true;
9981 case CSSPropertyOrientation: // auto | portrait | landscape
9982 if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandscape)
9983 validPrimitive = true;
9988 RefPtr<CSSValue> parsedValue;
9989 if (validPrimitive) {
9990 parsedValue = parseValidPrimitive(id, value);
9991 m_valueList->next();
9995 if (!m_valueList->current() || inShorthand()) {
9996 addProperty(propId, parsedValue.release(), important);
10004 bool BisonCSSParser::parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first, CSSPropertyID second, bool important)
10006 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
10007 unsigned numValues = m_valueList->size();
10012 ShorthandScope scope(this, propId);
10014 if (!parseViewportProperty(first, important))
10017 // If just one value is supplied, the second value
10018 // is implicitly initialized with the first value.
10019 if (numValues == 1)
10020 m_valueList->previous();
10022 return parseViewportProperty(second, important);
10025 template <typename CharacterType>
10026 static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
10028 char buffer[maxCSSPropertyNameLength + 1]; // 1 for null character
10030 for (unsigned i = 0; i != length; ++i) {
10031 CharacterType c = propertyName[i];
10032 if (c == 0 || c >= 0x7F)
10033 return CSSPropertyInvalid; // illegal character
10034 buffer[i] = toASCIILower(c);
10036 buffer[length] = '\0';
10038 const char* name = buffer;
10039 const Property* hashTableEntry = findProperty(name, length);
10040 return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
10043 CSSPropertyID cssPropertyID(const String& string)
10045 unsigned length = string.length();
10048 return CSSPropertyInvalid;
10049 if (length > maxCSSPropertyNameLength)
10050 return CSSPropertyInvalid;
10052 return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
10055 CSSPropertyID cssPropertyID(const CSSParserString& string)
10057 unsigned length = string.length();
10060 return CSSPropertyInvalid;
10061 if (length > maxCSSPropertyNameLength)
10062 return CSSPropertyInvalid;
10064 return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
10067 template <typename CharacterType>
10068 static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
10070 char buffer[maxCSSValueKeywordLength + 1]; // 1 for null character
10072 for (unsigned i = 0; i != length; ++i) {
10073 CharacterType c = valueKeyword[i];
10074 if (c == 0 || c >= 0x7F)
10075 return CSSValueInvalid; // illegal character
10076 buffer[i] = WTF::toASCIILower(c);
10078 buffer[length] = '\0';
10080 const Value* hashTableEntry = findValue(buffer, length);
10081 return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSValueInvalid;
10084 CSSValueID cssValueKeywordID(const CSSParserString& string)
10086 unsigned length = string.length();
10088 return CSSValueInvalid;
10089 if (length > maxCSSValueKeywordLength)
10090 return CSSValueInvalid;
10092 return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
10095 bool isValidNthToken(const CSSParserString& token)
10097 // The tokenizer checks for the construct of an+b.
10098 // However, since the {ident} rule precedes the {nth} rule, some of those
10099 // tokens are identified as string literal. Furthermore we need to accept
10100 // "odd" and "even" which does not match to an+b.
10101 return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
10102 || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");