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/CSSPropertyParser.h"
29 #include "RuntimeEnabledFeatures.h"
30 #include "core/rendering/RenderTheme.h"
31 #include "core/svg/SVGPaint.h"
32 // FIXME: Way too many!
33 #include "CSSValueKeywords.h"
34 #include "RuntimeEnabledFeatures.h"
35 #include "StylePropertyShorthand.h"
36 #include "core/css/CSSArrayFunctionValue.h"
37 #include "core/css/CSSAspectRatioValue.h"
38 #include "core/css/CSSBasicShapes.h"
39 #include "core/css/CSSBorderImage.h"
40 #include "core/css/CSSCanvasValue.h"
41 #include "core/css/CSSCrossfadeValue.h"
42 #include "core/css/CSSCursorImageValue.h"
43 #include "core/css/CSSFontFaceSrcValue.h"
44 #include "core/css/CSSFontFeatureValue.h"
45 #include "core/css/CSSFunctionValue.h"
46 #include "core/css/CSSGradientValue.h"
47 #include "core/css/CSSGridLineNamesValue.h"
48 #include "core/css/CSSGridTemplateAreasValue.h"
49 #include "core/css/CSSImageSetValue.h"
50 #include "core/css/CSSImageValue.h"
51 #include "core/css/CSSInheritedValue.h"
52 #include "core/css/CSSInitialValue.h"
53 #include "core/css/CSSKeyframeRule.h"
54 #include "core/css/CSSKeyframesRule.h"
55 #include "core/css/CSSLineBoxContainValue.h"
56 #include "core/css/CSSParserValues.h"
57 #include "core/css/CSSPrimitiveValue.h"
58 #include "core/css/CSSPropertySourceData.h"
59 #include "core/css/CSSReflectValue.h"
60 #include "core/css/CSSSVGDocumentValue.h"
61 #include "core/css/CSSSelector.h"
62 #include "core/css/CSSShadowValue.h"
63 #include "core/css/CSSTimingFunctionValue.h"
64 #include "core/css/CSSTransformValue.h"
65 #include "core/css/CSSUnicodeRangeValue.h"
66 #include "core/css/CSSValueList.h"
67 #include "core/css/CSSValuePool.h"
68 #include "core/css/Counter.h"
69 #include "core/css/HashTools.h"
70 #include "core/css/Pair.h"
71 #include "core/css/Rect.h"
72 #include "core/css/RuntimeCSSEnabled.h"
73 #include "core/css/parser/CSSParserIdioms.h"
74 #include "core/html/parser/HTMLParserIdioms.h"
75 #include "core/inspector/InspectorInstrumentation.h"
76 #include "core/rendering/RenderTheme.h"
77 #include "core/svg/SVGParserUtilities.h"
78 #include "platform/FloatConversion.h"
79 #include "wtf/BitArray.h"
80 #include "wtf/HexNumber.h"
81 #include "wtf/text/StringBuffer.h"
82 #include "wtf/text/StringBuilder.h"
83 #include "wtf/text/StringImpl.h"
84 #include "wtf/text/TextEncoding.h"
91 static const double MAX_SCALE = 1000000;
92 static const unsigned minRepetitions = 10000;
95 static bool equal(const CSSParserString& a, const char (&b)[N])
97 unsigned length = N - 1; // Ignore the trailing null character
98 if (a.length() != length)
101 return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar*>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length);
104 template <unsigned N>
105 static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
107 unsigned length = N - 1; // Ignore the trailing null character
108 if (a.length() != length)
111 return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length);
114 template <unsigned N>
115 static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N])
117 ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrimitiveValue::CSS_STRING);
118 return equalIgnoringCase(value->string, b);
121 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> first, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> second, Pair::IdenticalValuesPolicy identicalValuesPolicy = Pair::DropIdenticalValues)
123 return cssValuePool().createValue(Pair::create(first, second, identicalValuesPolicy));
126 class AnimationParseContext {
128 AnimationParseContext()
129 : m_animationPropertyKeywordAllowed(true)
130 , m_firstAnimationCommitted(false)
134 void commitFirstAnimation()
136 m_firstAnimationCommitted = true;
139 bool hasCommittedFirstAnimation() const
141 return m_firstAnimationCommitted;
144 void commitAnimationPropertyKeyword()
146 m_animationPropertyKeywordAllowed = false;
149 bool animationPropertyKeywordAllowed() const
151 return m_animationPropertyKeywordAllowed;
155 bool m_animationPropertyKeywordAllowed;
156 bool m_firstAnimationCommitted;
159 CSSPropertyParser::CSSPropertyParser(OwnPtr<CSSParserValueList>& valueList,
160 const CSSParserContext& context, bool inViewport, bool savedImportant,
161 WillBeHeapVector<CSSProperty, 256>& parsedProperties, bool& hasFontFaceOnlyValues)
162 : m_valueList(valueList)
164 , m_inViewport(inViewport)
165 , m_important(savedImportant) // See comment in header, should be removed.
166 , m_parsedProperties(parsedProperties)
167 , m_hasFontFaceOnlyValues(hasFontFaceOnlyValues)
168 , m_inParseShorthand(0)
169 , m_currentShorthand(CSSPropertyInvalid)
170 , m_implicitShorthand(false)
174 CSSPropertyParser::~CSSPropertyParser()
178 void CSSPropertyParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important, bool implicit)
180 RefPtrWillBeRawPtr<CSSValue> val = value.get();
181 addProperty(propId, value, important, implicit);
183 CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId);
184 if (prefixingVariant == propId)
187 if (m_currentShorthand) {
188 // We can't use ShorthandScope here as we can already be inside one (e.g we are parsing CSSTransition).
189 m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
190 addProperty(prefixingVariant, val.release(), important, implicit);
191 m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
193 addProperty(prefixingVariant, val.release(), important, implicit);
197 void CSSPropertyParser::addProperty(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important, bool implicit)
199 // This property doesn't belong to a shorthand.
200 if (!m_currentShorthand) {
201 m_parsedProperties.append(CSSProperty(propId, value, important, false, CSSPropertyInvalid, m_implicitShorthand || implicit));
205 Vector<StylePropertyShorthand, 4> shorthands;
206 getMatchingShorthandsForLonghand(propId, &shorthands);
207 // The longhand does not belong to multiple shorthands.
208 if (shorthands.size() == 1)
209 m_parsedProperties.append(CSSProperty(propId, value, important, true, CSSPropertyInvalid, m_implicitShorthand || implicit));
211 m_parsedProperties.append(CSSProperty(propId, value, important, true, indexOfShorthandForLonghand(m_currentShorthand, shorthands), m_implicitShorthand || implicit));
214 void CSSPropertyParser::rollbackLastProperties(int num)
217 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
218 m_parsedProperties.shrink(m_parsedProperties.size() - num);
221 KURL CSSPropertyParser::completeURL(const String& url) const
223 return m_context.completeURL(url);
226 bool CSSPropertyParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc)
228 bool mustBeNonNegative = unitflags & FNonNeg;
230 if (!parseCalculation(value, mustBeNonNegative ? ValueRangeNonNegative : ValueRangeAll))
234 switch (m_parsedCalculation->category()) {
236 b = (unitflags & FLength);
239 b = (unitflags & FPercent);
240 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
244 b = (unitflags & FNumber);
245 if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
247 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
250 case CalcPercentLength:
251 b = (unitflags & FPercent) && (unitflags & FLength);
253 case CalcPercentNumber:
254 b = (unitflags & FPercent) && (unitflags & FNumber);
259 if (!b || releaseCalc == ReleaseParsedCalcValue)
260 m_parsedCalculation.release();
264 inline bool CSSPropertyParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
266 // Quirks mode and presentation attributes accept unit less values.
267 return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || isUnitLessLengthParsingEnabledForMode(cssParserMode));
270 bool CSSPropertyParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
272 if (isCalculation(value))
273 return validCalculationUnit(value, unitflags, releaseCalc);
276 switch (value->unit) {
277 case CSSPrimitiveValue::CSS_NUMBER:
278 b = (unitflags & FNumber);
279 if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
280 value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
281 ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
284 if (!b && (unitflags & FInteger) && value->isInt)
286 if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0)
289 case CSSPrimitiveValue::CSS_PERCENTAGE:
290 b = (unitflags & FPercent);
292 case CSSParserValue::Q_EMS:
293 case CSSPrimitiveValue::CSS_EMS:
294 case CSSPrimitiveValue::CSS_REMS:
295 case CSSPrimitiveValue::CSS_CHS:
296 case CSSPrimitiveValue::CSS_EXS:
297 case CSSPrimitiveValue::CSS_PX:
298 case CSSPrimitiveValue::CSS_CM:
299 case CSSPrimitiveValue::CSS_MM:
300 case CSSPrimitiveValue::CSS_IN:
301 case CSSPrimitiveValue::CSS_PT:
302 case CSSPrimitiveValue::CSS_PC:
303 case CSSPrimitiveValue::CSS_VW:
304 case CSSPrimitiveValue::CSS_VH:
305 case CSSPrimitiveValue::CSS_VMIN:
306 case CSSPrimitiveValue::CSS_VMAX:
307 b = (unitflags & FLength);
309 case CSSPrimitiveValue::CSS_MS:
310 case CSSPrimitiveValue::CSS_S:
311 b = (unitflags & FTime);
313 case CSSPrimitiveValue::CSS_DEG:
314 case CSSPrimitiveValue::CSS_RAD:
315 case CSSPrimitiveValue::CSS_GRAD:
316 case CSSPrimitiveValue::CSS_TURN:
317 b = (unitflags & FAngle);
319 case CSSPrimitiveValue::CSS_DPPX:
320 case CSSPrimitiveValue::CSS_DPI:
321 case CSSPrimitiveValue::CSS_DPCM:
322 b = (unitflags & FResolution);
324 case CSSPrimitiveValue::CSS_HZ:
325 case CSSPrimitiveValue::CSS_KHZ:
326 case CSSPrimitiveValue::CSS_DIMENSION:
330 if (b && unitflags & FNonNeg && value->fValue < 0)
335 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimitiveNumericValue(CSSParserValue* value)
337 if (m_parsedCalculation) {
338 ASSERT(isCalculation(value));
339 return CSSPrimitiveValue::create(m_parsedCalculation.release());
342 ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
343 || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
344 || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
345 || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
346 return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
349 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimitiveStringValue(CSSParserValue* value)
351 ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
352 return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
355 inline PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::createCSSImageValueWithReferrer(const String& rawValue, const KURL& url)
357 RefPtrWillBeRawPtr<CSSValue> imageValue = CSSImageValue::create(rawValue, url);
358 toCSSImageValue(imageValue.get())->setReferrer(m_context.baseURL().strippedForUseAsReferrer());
362 static inline bool isComma(CSSParserValue* value)
364 return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
367 static inline bool isForwardSlashOperator(CSSParserValue* value)
370 return value->unit == CSSParserValue::Operator && value->iValue == '/';
373 static bool isGeneratedImageValue(CSSParserValue* val)
375 if (val->unit != CSSParserValue::Function)
378 return equalIgnoringCase(val->function->name, "-webkit-gradient(")
379 || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
380 || equalIgnoringCase(val->function->name, "linear-gradient(")
381 || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
382 || equalIgnoringCase(val->function->name, "repeating-linear-gradient(")
383 || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
384 || equalIgnoringCase(val->function->name, "radial-gradient(")
385 || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
386 || equalIgnoringCase(val->function->name, "repeating-radial-gradient(")
387 || equalIgnoringCase(val->function->name, "-webkit-canvas(")
388 || equalIgnoringCase(val->function->name, "-webkit-cross-fade(");
391 bool CSSPropertyParser::validWidthOrHeight(CSSParserValue* value)
394 if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
396 return !id && validUnit(value, FLength | FPercent | FNonNeg);
399 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value)
402 return cssValuePool().createIdentifierValue(identifier);
403 if (value->unit == CSSPrimitiveValue::CSS_STRING)
404 return createPrimitiveStringValue(value);
405 if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
406 return createPrimitiveNumericValue(value);
407 if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
408 return createPrimitiveNumericValue(value);
409 if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
410 return createPrimitiveNumericValue(value);
411 if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
412 return createPrimitiveNumericValue(value);
413 if (value->unit >= CSSParserValue::Q_EMS)
414 return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
415 if (isCalculation(value))
416 return CSSPrimitiveValue::create(m_parsedCalculation.release());
421 void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> prpValue, bool important)
423 const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
424 unsigned shorthandLength = shorthand.length();
425 if (!shorthandLength) {
426 addPropertyWithPrefixingVariant(propId, prpValue, important);
430 RefPtrWillBeRawPtr<CSSValue> value = prpValue;
431 ShorthandScope scope(this, propId);
432 const CSSPropertyID* longhands = shorthand.properties();
433 for (unsigned i = 0; i < shorthandLength; ++i)
434 addPropertyWithPrefixingVariant(longhands[i], value, important);
437 bool CSSPropertyParser::parseValue(CSSPropertyID propId, bool important)
439 if (!isInternalPropertyAndValueParsingEnabledForMode(m_context.mode()) && isInternalProperty(propId))
442 // We don't count the UA style sheet in our statistics.
443 if (m_context.useCounter())
444 m_context.useCounter()->count(m_context, propId);
449 CSSParserValue* value = m_valueList->current();
455 // Allow @viewport rules from UA stylesheets even if the feature is disabled.
456 if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode()))
459 return parseViewportProperty(propId, important);
462 // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
463 // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
464 ASSERT(!m_parsedCalculation);
466 CSSValueID id = value->id;
468 int num = inShorthand() ? 1 : m_valueList->size();
470 if (id == CSSValueInherit) {
473 addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important);
476 else if (id == CSSValueInitial) {
479 addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important);
483 if (isKeywordPropertyID(propId)) {
484 if (!isValidKeywordPropertyAndValue(propId, id, m_context))
486 if (m_valueList->next() && !inShorthand())
488 addProperty(propId, cssValuePool().createIdentifierValue(id), important);
492 bool validPrimitive = false;
493 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
496 case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
497 return parseSize(propId, important);
499 case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit
501 validPrimitive = true;
503 return parseQuotes(propId, important);
505 case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | isolate-override | plaintext | inherit
506 if (id == CSSValueNormal
507 || id == CSSValueEmbed
508 || id == CSSValueBidiOverride
509 || id == CSSValueWebkitIsolate
510 || id == CSSValueWebkitIsolateOverride
511 || id == CSSValueWebkitPlaintext)
512 validPrimitive = true;
515 case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
516 // close-quote | no-open-quote | no-close-quote ]+ | inherit
517 return parseContent(propId, important);
519 case CSSPropertyClip: // <shape> | auto | inherit
520 if (id == CSSValueAuto)
521 validPrimitive = true;
522 else if (value->unit == CSSParserValue::Function)
523 return parseClipShape(propId, important);
526 /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
527 * correctly and allows optimization in WebCore::applyRule(..)
529 case CSSPropertyOverflow: {
530 ShorthandScope scope(this, propId);
531 if (num != 1 || !parseValue(CSSPropertyOverflowY, important))
534 RefPtrWillBeRawPtr<CSSValue> overflowXValue = nullptr;
536 // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been
537 // set using the shorthand, then for now overflow-x will default to auto, but once we implement
538 // pagination controls, it should default to hidden. If the overflow-y value is anything but
539 // paged-x or paged-y, then overflow-x and overflow-y should have the same value.
540 if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
541 overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
543 overflowXValue = m_parsedProperties.last().value();
544 addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
548 case CSSPropertyTextAlign:
549 // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
550 // | start | end | <string> | inherit | -webkit-auto (converted to start)
551 if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
552 || value->unit == CSSPrimitiveValue::CSS_STRING)
553 validPrimitive = true;
556 case CSSPropertyFontWeight: { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
557 if (m_valueList->size() != 1)
559 return parseFontWeight(important);
561 case CSSPropertyBorderSpacing: {
563 ShorthandScope scope(this, CSSPropertyBorderSpacing);
564 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
566 CSSValue* value = m_parsedProperties.last().value();
567 addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
571 ShorthandScope scope(this, CSSPropertyBorderSpacing);
572 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
578 case CSSPropertyWebkitBorderHorizontalSpacing:
579 case CSSPropertyWebkitBorderVerticalSpacing:
580 validPrimitive = validUnit(value, FLength | FNonNeg);
582 case CSSPropertyOutlineColor: // <color> | invert | inherit
583 // Outline color has "invert" as additional keyword.
584 // Also, we want to allow the special focus color even in HTML Standard parsing mode.
585 if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
586 validPrimitive = true;
590 case CSSPropertyBackgroundColor: // <color> | inherit
591 case CSSPropertyBorderTopColor: // <color> | inherit
592 case CSSPropertyBorderRightColor:
593 case CSSPropertyBorderBottomColor:
594 case CSSPropertyBorderLeftColor:
595 case CSSPropertyWebkitBorderStartColor:
596 case CSSPropertyWebkitBorderEndColor:
597 case CSSPropertyWebkitBorderBeforeColor:
598 case CSSPropertyWebkitBorderAfterColor:
599 case CSSPropertyColor: // <color> | inherit
600 case CSSPropertyTextDecorationColor: // CSS3 text decoration colors
601 case CSSPropertyTextLineThroughColor:
602 case CSSPropertyTextUnderlineColor:
603 case CSSPropertyTextOverlineColor:
604 case CSSPropertyWebkitColumnRuleColor:
605 case CSSPropertyWebkitTextEmphasisColor:
606 case CSSPropertyWebkitTextFillColor:
607 case CSSPropertyWebkitTextStrokeColor:
608 if (propId == CSSPropertyTextDecorationColor
609 && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
612 if ((id >= CSSValueAqua && id <= CSSValueWebkitText) || id == CSSValueMenu) {
613 validPrimitive = isValueAllowedInMode(id, m_context.mode());
615 parsedValue = parseColor();
621 case CSSPropertyCursor: {
622 // Grammar defined by CSS3 UI and modified by CSS4 images:
623 // [ [<image> [<x> <y>]?,]*
624 // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
625 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
626 // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
627 // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
628 // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
629 RefPtrWillBeRawPtr<CSSValueList> list = nullptr;
631 RefPtrWillBeRawPtr<CSSValue> image = nullptr;
632 if (value->unit == CSSPrimitiveValue::CSS_URI) {
633 String uri = value->string;
635 image = createCSSImageValueWithReferrer(uri, completeURL(uri));
636 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
637 image = parseImageSet(m_valueList.get());
644 value = m_valueList->next();
645 while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
646 coords.append(int(value->fValue));
647 value = m_valueList->next();
649 bool hasHotSpot = false;
650 IntPoint hotSpot(-1, -1);
651 int nrcoords = coords.size();
652 if (nrcoords > 0 && nrcoords != 2)
656 hotSpot = IntPoint(coords[0], coords[1]);
660 list = CSSValueList::createCommaSeparated();
663 list->append(CSSCursorImageValue::create(image, hasHotSpot, hotSpot));
665 if (!value || !(value->unit == CSSParserValue::Operator && value->iValue == ','))
667 value = m_valueList->next(); // comma
672 if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
673 list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
674 else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
675 list->append(cssValuePool().createIdentifierValue(value->id));
677 parsedValue = list.release();
681 if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
682 id = CSSValuePointer;
683 validPrimitive = true;
684 } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
685 validPrimitive = true;
687 ASSERT_NOT_REACHED();
693 case CSSPropertyBackgroundBlendMode:
694 case CSSPropertyBackgroundAttachment:
695 case CSSPropertyBackgroundClip:
696 case CSSPropertyWebkitBackgroundClip:
697 case CSSPropertyWebkitBackgroundComposite:
698 case CSSPropertyBackgroundImage:
699 case CSSPropertyBackgroundOrigin:
700 case CSSPropertyMaskSourceType:
701 case CSSPropertyWebkitBackgroundOrigin:
702 case CSSPropertyBackgroundPosition:
703 case CSSPropertyBackgroundPositionX:
704 case CSSPropertyBackgroundPositionY:
705 case CSSPropertyBackgroundSize:
706 case CSSPropertyWebkitBackgroundSize:
707 case CSSPropertyBackgroundRepeat:
708 case CSSPropertyBackgroundRepeatX:
709 case CSSPropertyBackgroundRepeatY:
710 case CSSPropertyWebkitMaskClip:
711 case CSSPropertyWebkitMaskComposite:
712 case CSSPropertyWebkitMaskImage:
713 case CSSPropertyWebkitMaskOrigin:
714 case CSSPropertyWebkitMaskPosition:
715 case CSSPropertyWebkitMaskPositionX:
716 case CSSPropertyWebkitMaskPositionY:
717 case CSSPropertyWebkitMaskSize:
718 case CSSPropertyWebkitMaskRepeat:
719 case CSSPropertyWebkitMaskRepeatX:
720 case CSSPropertyWebkitMaskRepeatY:
722 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
723 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
724 CSSPropertyID propId1, propId2;
726 if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
727 if (propId == CSSPropertyBackgroundPosition ||
728 propId == CSSPropertyBackgroundRepeat ||
729 propId == CSSPropertyWebkitMaskPosition ||
730 propId == CSSPropertyWebkitMaskRepeat) {
731 ShorthandScope scope(this, propId);
732 addProperty(propId1, val1.release(), important);
734 addProperty(propId2, val2.release(), important);
736 addProperty(propId1, val1.release(), important);
738 addProperty(propId2, val2.release(), important);
742 m_implicitShorthand = false;
745 case CSSPropertyObjectPosition:
746 return RuntimeEnabledFeatures::objectFitPositionEnabled() && parseObjectPosition(important);
747 case CSSPropertyListStyleImage: // <uri> | none | inherit
748 case CSSPropertyBorderImageSource:
749 case CSSPropertyWebkitMaskBoxImageSource:
750 if (id == CSSValueNone) {
751 parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
753 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
754 parsedValue = createCSSImageValueWithReferrer(value->string, completeURL(value->string));
756 } else if (isGeneratedImageValue(value)) {
757 if (parseGeneratedImage(m_valueList.get(), parsedValue))
762 else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
763 parsedValue = parseImageSet(m_valueList.get());
770 case CSSPropertyWebkitTextStrokeWidth:
771 case CSSPropertyOutlineWidth: // <border-width> | inherit
772 case CSSPropertyBorderTopWidth: //// <border-width> | inherit
773 case CSSPropertyBorderRightWidth: // Which is defined as
774 case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
775 case CSSPropertyBorderLeftWidth:
776 case CSSPropertyWebkitBorderStartWidth:
777 case CSSPropertyWebkitBorderEndWidth:
778 case CSSPropertyWebkitBorderBeforeWidth:
779 case CSSPropertyWebkitBorderAfterWidth:
780 case CSSPropertyWebkitColumnRuleWidth:
781 if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
782 validPrimitive = true;
784 validPrimitive = validUnit(value, FLength | FNonNeg);
787 case CSSPropertyLetterSpacing: // normal | <length> | inherit
788 case CSSPropertyWordSpacing: // normal | <length> | inherit
789 if (id == CSSValueNormal)
790 validPrimitive = true;
792 validPrimitive = validUnit(value, FLength);
795 case CSSPropertyTextIndent:
796 parsedValue = parseTextIndent();
799 case CSSPropertyPaddingTop: //// <padding-width> | inherit
800 case CSSPropertyPaddingRight: // Which is defined as
801 case CSSPropertyPaddingBottom: // <length> | <percentage>
802 case CSSPropertyPaddingLeft: ////
803 case CSSPropertyWebkitPaddingStart:
804 case CSSPropertyWebkitPaddingEnd:
805 case CSSPropertyWebkitPaddingBefore:
806 case CSSPropertyWebkitPaddingAfter:
807 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
810 case CSSPropertyMaxWidth:
811 case CSSPropertyWebkitMaxLogicalWidth:
812 case CSSPropertyMaxHeight:
813 case CSSPropertyWebkitMaxLogicalHeight:
814 validPrimitive = (id == CSSValueNone || validWidthOrHeight(value));
817 case CSSPropertyMinWidth:
818 case CSSPropertyWebkitMinLogicalWidth:
819 case CSSPropertyMinHeight:
820 case CSSPropertyWebkitMinLogicalHeight:
821 validPrimitive = validWidthOrHeight(value);
824 case CSSPropertyWidth:
825 case CSSPropertyWebkitLogicalWidth:
826 case CSSPropertyHeight:
827 case CSSPropertyWebkitLogicalHeight:
828 validPrimitive = (id == CSSValueAuto || validWidthOrHeight(value));
831 case CSSPropertyFontSize:
832 return parseFontSize(important);
834 case CSSPropertyFontVariant: // normal | small-caps | inherit
835 return parseFontVariant(important);
837 case CSSPropertyVerticalAlign:
838 // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
839 // <percentage> | <length> | inherit
841 if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
842 validPrimitive = true;
844 validPrimitive = (!id && validUnit(value, FLength | FPercent));
847 case CSSPropertyBottom: // <length> | <percentage> | auto | inherit
848 case CSSPropertyLeft: // <length> | <percentage> | auto | inherit
849 case CSSPropertyRight: // <length> | <percentage> | auto | inherit
850 case CSSPropertyTop: // <length> | <percentage> | auto | inherit
851 case CSSPropertyMarginTop: //// <margin-width> | inherit
852 case CSSPropertyMarginRight: // Which is defined as
853 case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit
854 case CSSPropertyMarginLeft: ////
855 case CSSPropertyWebkitMarginStart:
856 case CSSPropertyWebkitMarginEnd:
857 case CSSPropertyWebkitMarginBefore:
858 case CSSPropertyWebkitMarginAfter:
859 if (id == CSSValueAuto)
860 validPrimitive = true;
862 validPrimitive = (!id && validUnit(value, FLength | FPercent));
865 case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
866 case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
867 if (id == CSSValueAuto)
868 validPrimitive = true;
870 validPrimitive = (!id && validUnit(value, FPositiveInteger, HTMLQuirksMode));
873 case CSSPropertyZIndex: // auto | <integer> | inherit
874 if (id == CSSValueAuto)
875 validPrimitive = true;
877 validPrimitive = (!id && validUnit(value, FInteger, HTMLQuirksMode));
880 case CSSPropertyLineHeight:
881 return parseLineHeight(important);
882 case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
883 if (id != CSSValueNone)
884 return parseCounter(propId, 1, important);
885 validPrimitive = true;
887 case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit
888 if (id != CSSValueNone)
889 return parseCounter(propId, 0, important);
890 validPrimitive = true;
892 case CSSPropertyFontFamily:
893 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
895 parsedValue = parseFontFamily();
899 case CSSPropertyTextDecoration:
900 // Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration
901 // is disabled to match CSS 2.1 rules for parsing 'text-decoration'.
902 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) {
903 // [ <text-decoration-line> || <text-decoration-style> || <text-decoration-color> ] | inherit
904 return parseShorthand(CSSPropertyTextDecoration, textDecorationShorthand(), important);
906 case CSSPropertyWebkitTextDecorationsInEffect:
907 case CSSPropertyTextDecorationLine:
908 // none | [ underline || overline || line-through || blink ] | inherit
909 return parseTextDecoration(propId, important);
911 case CSSPropertyTextDecorationStyle:
912 // solid | double | dotted | dashed | wavy
913 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()
914 && (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDotted || id == CSSValueDashed || id == CSSValueWavy))
915 validPrimitive = true;
918 case CSSPropertyTextUnderlinePosition:
919 // auto | under | inherit
920 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled())
921 return parseTextUnderlinePosition(important);
924 case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit
925 if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
926 validPrimitive = true;
928 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode));
931 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.
932 return parseFontFaceSrc();
934 case CSSPropertyUnicodeRange:
935 return parseFontFaceUnicodeRange();
937 /* CSS3 properties */
939 case CSSPropertyBorderImage:
940 case CSSPropertyWebkitMaskBoxImage:
941 return parseBorderImageShorthand(propId, important);
942 case CSSPropertyWebkitBorderImage: {
943 if (RefPtrWillBeRawPtr<CSSValue> result = parseBorderImage(propId)) {
944 addProperty(propId, result, important);
950 case CSSPropertyBorderImageOutset:
951 case CSSPropertyWebkitMaskBoxImageOutset: {
952 RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
953 if (parseBorderImageOutset(result)) {
954 addProperty(propId, result, important);
959 case CSSPropertyBorderImageRepeat:
960 case CSSPropertyWebkitMaskBoxImageRepeat: {
961 RefPtrWillBeRawPtr<CSSValue> result = nullptr;
962 if (parseBorderImageRepeat(result)) {
963 addProperty(propId, result, important);
968 case CSSPropertyBorderImageSlice:
969 case CSSPropertyWebkitMaskBoxImageSlice: {
970 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> result = nullptr;
971 if (parseBorderImageSlice(propId, result)) {
972 addProperty(propId, result, important);
977 case CSSPropertyBorderImageWidth:
978 case CSSPropertyWebkitMaskBoxImageWidth: {
979 RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
980 if (parseBorderImageWidth(result)) {
981 addProperty(propId, result, important);
986 case CSSPropertyBorderTopRightRadius:
987 case CSSPropertyBorderTopLeftRadius:
988 case CSSPropertyBorderBottomLeftRadius:
989 case CSSPropertyBorderBottomRightRadius: {
990 if (num != 1 && num != 2)
992 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
995 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
996 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr;
998 value = m_valueList->next();
999 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
1000 if (!validPrimitive)
1002 parsedValue2 = createPrimitiveNumericValue(value);
1004 parsedValue2 = parsedValue1;
1006 addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important);
1009 case CSSPropertyTabSize:
1010 validPrimitive = validUnit(value, FInteger | FNonNeg);
1012 case CSSPropertyWebkitAspectRatio:
1013 return parseAspectRatio(important);
1014 case CSSPropertyBorderRadius:
1015 case CSSPropertyWebkitBorderRadius:
1016 return parseBorderRadius(propId, important);
1017 case CSSPropertyOutlineOffset:
1018 validPrimitive = validUnit(value, FLength);
1020 case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
1021 case CSSPropertyBoxShadow:
1022 case CSSPropertyWebkitBoxShadow:
1023 if (id == CSSValueNone)
1024 validPrimitive = true;
1026 RefPtrWillBeRawPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
1027 if (shadowValueList) {
1028 addProperty(propId, shadowValueList.release(), important);
1029 m_valueList->next();
1035 case CSSPropertyWebkitBoxReflect:
1036 if (id == CSSValueNone)
1037 validPrimitive = true;
1039 return parseReflect(propId, important);
1041 case CSSPropertyOpacity:
1042 validPrimitive = validUnit(value, FNumber);
1044 case CSSPropertyWebkitBoxFlex:
1045 validPrimitive = validUnit(value, FNumber);
1047 case CSSPropertyWebkitBoxFlexGroup:
1048 validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode);
1050 case CSSPropertyWebkitBoxOrdinalGroup:
1051 validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode) && value->fValue;
1053 case CSSPropertyWebkitFilter:
1054 if (id == CSSValueNone)
1055 validPrimitive = true;
1057 RefPtrWillBeRawPtr<CSSValue> val = parseFilter();
1059 addProperty(propId, val, important);
1065 case CSSPropertyFlex: {
1066 ShorthandScope scope(this, propId);
1067 if (id == CSSValueNone) {
1068 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
1069 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
1070 addProperty(CSSPropertyFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
1073 return parseFlex(m_valueList.get(), important);
1075 case CSSPropertyFlexBasis:
1076 // FIXME: Support intrinsic dimensions too.
1077 if (id == CSSValueAuto)
1078 validPrimitive = true;
1080 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
1082 case CSSPropertyFlexGrow:
1083 case CSSPropertyFlexShrink:
1084 validPrimitive = validUnit(value, FNumber | FNonNeg);
1086 case CSSPropertyOrder:
1087 validPrimitive = validUnit(value, FInteger, HTMLStandardMode);
1089 case CSSPropertyInternalMarqueeIncrement:
1090 if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
1091 validPrimitive = true;
1093 validPrimitive = validUnit(value, FLength | FPercent);
1095 case CSSPropertyInternalMarqueeRepetition:
1096 if (id == CSSValueInfinite)
1097 validPrimitive = true;
1099 validPrimitive = validUnit(value, FInteger | FNonNeg);
1101 case CSSPropertyInternalMarqueeSpeed:
1102 if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
1103 validPrimitive = true;
1105 validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
1107 case CSSPropertyTransform:
1108 case CSSPropertyWebkitTransform:
1109 if (id == CSSValueNone)
1110 validPrimitive = true;
1112 RefPtrWillBeRawPtr<CSSValue> transformValue = parseTransform(propId);
1113 if (transformValue) {
1114 addProperty(propId, transformValue.release(), important);
1120 case CSSPropertyTransformOrigin: {
1121 RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin();
1124 // These values are added to match gecko serialization.
1125 if (list->length() == 1)
1126 list->append(cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
1127 if (list->length() == 2)
1128 list->append(cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX));
1129 addProperty(propId, list.release(), important);
1132 case CSSPropertyWebkitTransformOrigin:
1133 case CSSPropertyWebkitTransformOriginX:
1134 case CSSPropertyWebkitTransformOriginY:
1135 case CSSPropertyWebkitTransformOriginZ: {
1136 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
1137 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
1138 RefPtrWillBeRawPtr<CSSValue> val3 = nullptr;
1139 CSSPropertyID propId1, propId2, propId3;
1140 if (parseWebkitTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
1141 addProperty(propId1, val1.release(), important);
1143 addProperty(propId2, val2.release(), important);
1145 addProperty(propId3, val3.release(), important);
1150 case CSSPropertyPerspective:
1151 if (id == CSSValueNone) {
1152 validPrimitive = true;
1153 } else if (validUnit(value, FLength | FNonNeg)) {
1154 addProperty(propId, createPrimitiveNumericValue(value), important);
1158 case CSSPropertyWebkitPerspective:
1159 if (id == CSSValueNone) {
1160 validPrimitive = true;
1161 } else if (validUnit(value, FNumber | FLength | FNonNeg)) {
1162 // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
1163 addProperty(propId, createPrimitiveNumericValue(value), important);
1167 case CSSPropertyPerspectiveOrigin: {
1168 RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin();
1169 if (!list || list->length() == 3)
1171 // This values are added to match gecko serialization.
1172 if (list->length() == 1)
1173 list->append(cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
1174 addProperty(propId, list.release(), important);
1177 case CSSPropertyWebkitPerspectiveOrigin:
1178 case CSSPropertyWebkitPerspectiveOriginX:
1179 case CSSPropertyWebkitPerspectiveOriginY: {
1180 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
1181 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
1182 CSSPropertyID propId1, propId2;
1183 if (parseWebkitPerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
1184 addProperty(propId1, val1.release(), important);
1186 addProperty(propId2, val2.release(), important);
1191 case CSSPropertyAnimationDelay:
1192 case CSSPropertyAnimationDirection:
1193 case CSSPropertyAnimationDuration:
1194 case CSSPropertyAnimationFillMode:
1195 case CSSPropertyAnimationName:
1196 case CSSPropertyAnimationPlayState:
1197 case CSSPropertyAnimationIterationCount:
1198 case CSSPropertyAnimationTimingFunction:
1199 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
1201 case CSSPropertyWebkitAnimationDelay:
1202 case CSSPropertyWebkitAnimationDirection:
1203 case CSSPropertyWebkitAnimationDuration:
1204 case CSSPropertyWebkitAnimationFillMode:
1205 case CSSPropertyWebkitAnimationName:
1206 case CSSPropertyWebkitAnimationPlayState:
1207 case CSSPropertyWebkitAnimationIterationCount:
1208 case CSSPropertyWebkitAnimationTimingFunction:
1209 case CSSPropertyTransitionDelay:
1210 case CSSPropertyTransitionDuration:
1211 case CSSPropertyTransitionTimingFunction:
1212 case CSSPropertyTransitionProperty:
1213 case CSSPropertyWebkitTransitionDelay:
1214 case CSSPropertyWebkitTransitionDuration:
1215 case CSSPropertyWebkitTransitionTimingFunction:
1216 case CSSPropertyWebkitTransitionProperty: {
1217 RefPtrWillBeRawPtr<CSSValue> val = nullptr;
1218 AnimationParseContext context;
1219 if (parseAnimationProperty(propId, val, context)) {
1220 addPropertyWithPrefixingVariant(propId, val.release(), important);
1226 case CSSPropertyJustifySelf:
1227 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1230 return parseItemPositionOverflowPosition(propId, important);
1231 case CSSPropertyGridAutoColumns:
1232 case CSSPropertyGridAutoRows:
1233 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1235 parsedValue = parseGridTrackSize(*m_valueList);
1238 case CSSPropertyGridTemplateColumns:
1239 case CSSPropertyGridTemplateRows:
1240 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1242 parsedValue = parseGridTrackList(important);
1245 case CSSPropertyGridColumnEnd:
1246 case CSSPropertyGridColumnStart:
1247 case CSSPropertyGridRowEnd:
1248 case CSSPropertyGridRowStart:
1249 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1251 parsedValue = parseGridPosition();
1254 case CSSPropertyGridColumn:
1255 case CSSPropertyGridRow:
1256 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1258 return parseGridItemPositionShorthand(propId, important);
1260 case CSSPropertyGridArea:
1261 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1263 return parseGridAreaShorthand(important);
1265 case CSSPropertyGridTemplateAreas:
1266 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1268 parsedValue = parseGridTemplateAreas();
1271 case CSSPropertyGridTemplate:
1272 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1274 return parseGridTemplateShorthand(important);
1276 case CSSPropertyGrid:
1277 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1279 return parseGridShorthand(important);
1281 case CSSPropertyWebkitMarginCollapse: {
1283 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
1284 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important))
1286 CSSValue* value = m_parsedProperties.last().value();
1287 addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
1290 else if (num == 2) {
1291 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
1292 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important) || !parseValue(webkitMarginCollapseShorthand().properties()[1], important))
1298 case CSSPropertyTextLineThroughWidth:
1299 case CSSPropertyTextOverlineWidth:
1300 case CSSPropertyTextUnderlineWidth:
1301 if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
1302 id == CSSValueMedium || id == CSSValueThick)
1303 validPrimitive = true;
1305 validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent);
1307 case CSSPropertyWebkitColumnCount:
1308 parsedValue = parseColumnCount();
1310 case CSSPropertyWebkitColumnGap: // normal | <length>
1311 if (id == CSSValueNormal)
1312 validPrimitive = true;
1314 validPrimitive = validUnit(value, FLength | FNonNeg);
1316 case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property)
1317 if (id == CSSValueAll || id == CSSValueNone)
1318 validPrimitive = true;
1320 validPrimitive = validUnit(value, FNumber | FNonNeg) && value->fValue == 1;
1322 case CSSPropertyWebkitColumnWidth: // auto | <length>
1323 parsedValue = parseColumnWidth();
1325 case CSSPropertyWillChange:
1326 if (!RuntimeEnabledFeatures::cssWillChangeEnabled())
1328 return parseWillChange(important);
1329 // End of CSS3 properties
1331 // Apple specific properties. These will never be standardized and are purely to
1332 // support custom WebKit-based Apple applications.
1333 case CSSPropertyWebkitLineClamp:
1334 // When specifying number of lines, don't allow 0 as a valid value
1335 // When specifying either type of unit, require non-negative integers
1336 validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, HTMLQuirksMode));
1339 case CSSPropertyWebkitFontSizeDelta: // <length>
1340 validPrimitive = validUnit(value, FLength);
1343 case CSSPropertyWebkitHighlight:
1344 if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
1345 validPrimitive = true;
1348 case CSSPropertyWebkitHyphenateCharacter:
1349 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
1350 validPrimitive = true;
1353 case CSSPropertyWebkitLocale:
1354 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
1355 validPrimitive = true;
1358 // End Apple-specific properties
1360 case CSSPropertyWebkitAppRegion:
1361 if (id >= CSSValueDrag && id <= CSSValueNoDrag)
1362 validPrimitive = true;
1365 case CSSPropertyWebkitTapHighlightColor:
1366 if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu
1367 || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
1368 validPrimitive = true;
1370 parsedValue = parseColor();
1372 m_valueList->next();
1376 /* shorthand properties */
1377 case CSSPropertyBackground: {
1378 // Position must come before color in this array because a plain old "0" is a legal color
1379 // in quirks mode but it's usually the X coordinate of a position.
1380 const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
1381 CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
1382 CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
1383 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
1385 case CSSPropertyWebkitMask: {
1386 const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
1387 CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize };
1388 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
1390 case CSSPropertyBorder:
1391 // [ 'border-width' || 'border-style' || <color> ] | inherit
1393 if (parseShorthand(propId, parsingShorthandForProperty(CSSPropertyBorder), important)) {
1394 // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as
1395 // though a value of none was specified for the image.
1396 addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
1401 case CSSPropertyBorderTop:
1402 // [ 'border-top-width' || 'border-style' || <color> ] | inherit
1403 return parseShorthand(propId, borderTopShorthand(), important);
1404 case CSSPropertyBorderRight:
1405 // [ 'border-right-width' || 'border-style' || <color> ] | inherit
1406 return parseShorthand(propId, borderRightShorthand(), important);
1407 case CSSPropertyBorderBottom:
1408 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
1409 return parseShorthand(propId, borderBottomShorthand(), important);
1410 case CSSPropertyBorderLeft:
1411 // [ 'border-left-width' || 'border-style' || <color> ] | inherit
1412 return parseShorthand(propId, borderLeftShorthand(), important);
1413 case CSSPropertyWebkitBorderStart:
1414 return parseShorthand(propId, webkitBorderStartShorthand(), important);
1415 case CSSPropertyWebkitBorderEnd:
1416 return parseShorthand(propId, webkitBorderEndShorthand(), important);
1417 case CSSPropertyWebkitBorderBefore:
1418 return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
1419 case CSSPropertyWebkitBorderAfter:
1420 return parseShorthand(propId, webkitBorderAfterShorthand(), important);
1421 case CSSPropertyOutline:
1422 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
1423 return parseShorthand(propId, outlineShorthand(), important);
1424 case CSSPropertyBorderColor:
1425 // <color>{1,4} | inherit
1426 return parse4Values(propId, borderColorShorthand().properties(), important);
1427 case CSSPropertyBorderWidth:
1428 // <border-width>{1,4} | inherit
1429 return parse4Values(propId, borderWidthShorthand().properties(), important);
1430 case CSSPropertyBorderStyle:
1431 // <border-style>{1,4} | inherit
1432 return parse4Values(propId, borderStyleShorthand().properties(), important);
1433 case CSSPropertyMargin:
1434 // <margin-width>{1,4} | inherit
1435 return parse4Values(propId, marginShorthand().properties(), important);
1436 case CSSPropertyPadding:
1437 // <padding-width>{1,4} | inherit
1438 return parse4Values(propId, paddingShorthand().properties(), important);
1439 case CSSPropertyFlexFlow:
1440 return parseShorthand(propId, flexFlowShorthand(), important);
1441 case CSSPropertyFont:
1442 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
1443 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
1444 if (id >= CSSValueCaption && id <= CSSValueStatusBar)
1445 validPrimitive = true;
1447 return parseFont(important);
1449 case CSSPropertyListStyle:
1450 return parseShorthand(propId, listStyleShorthand(), important);
1451 case CSSPropertyWebkitColumns:
1452 return parseColumnsShorthand(important);
1453 case CSSPropertyWebkitColumnRule:
1454 return parseShorthand(propId, webkitColumnRuleShorthand(), important);
1455 case CSSPropertyWebkitTextStroke:
1456 return parseShorthand(propId, webkitTextStrokeShorthand(), important);
1457 case CSSPropertyAnimation:
1458 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
1460 case CSSPropertyWebkitAnimation:
1461 return parseAnimationShorthand(propId, important);
1462 case CSSPropertyTransition:
1463 case CSSPropertyWebkitTransition:
1464 return parseTransitionShorthand(propId, important);
1465 case CSSPropertyInvalid:
1467 case CSSPropertyPage:
1468 return parsePage(propId, important);
1469 case CSSPropertyFontStretch:
1471 // CSS Text Layout Module Level 3: Vertical writing support
1472 case CSSPropertyWebkitTextEmphasis:
1473 return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
1475 case CSSPropertyWebkitTextEmphasisStyle:
1476 return parseTextEmphasisStyle(important);
1478 case CSSPropertyWebkitTextOrientation:
1479 // FIXME: For now just support sideways, sideways-right, upright and vertical-right.
1480 if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSValueVerticalRight || id == CSSValueUpright)
1481 validPrimitive = true;
1484 case CSSPropertyWebkitLineBoxContain:
1485 if (id == CSSValueNone)
1486 validPrimitive = true;
1488 return parseLineBoxContain(important);
1490 case CSSPropertyWebkitFontFeatureSettings:
1491 if (id == CSSValueNormal)
1492 validPrimitive = true;
1494 return parseFontFeatureSettings(important);
1497 case CSSPropertyFontVariantLigatures:
1498 if (id == CSSValueNormal)
1499 validPrimitive = true;
1501 return parseFontVariantLigatures(important);
1503 case CSSPropertyWebkitClipPath:
1504 if (id == CSSValueNone) {
1505 validPrimitive = true;
1506 } else if (value->unit == CSSParserValue::Function) {
1507 parsedValue = parseBasicShape();
1508 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
1509 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
1510 addProperty(propId, parsedValue.release(), important);
1514 case CSSPropertyShapeOutside:
1515 parsedValue = parseShapeProperty(propId);
1517 case CSSPropertyShapeMargin:
1518 validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FLength | FPercent | FNonNeg));
1520 case CSSPropertyShapeImageThreshold:
1521 validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FNumber));
1524 case CSSPropertyTouchAction:
1525 // auto | none | [pan-x || pan-y] | manipulation
1526 return parseTouchAction(important);
1528 case CSSPropertyAlignSelf:
1529 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1530 return parseItemPositionOverflowPosition(propId, important);
1532 case CSSPropertyAlignItems:
1533 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1534 return parseItemPositionOverflowPosition(propId, important);
1536 case CSSPropertyBorderBottomStyle:
1537 case CSSPropertyBorderCollapse:
1538 case CSSPropertyBorderLeftStyle:
1539 case CSSPropertyBorderRightStyle:
1540 case CSSPropertyBorderTopStyle:
1541 case CSSPropertyBoxSizing:
1542 case CSSPropertyCaptionSide:
1543 case CSSPropertyClear:
1544 case CSSPropertyDirection:
1545 case CSSPropertyDisplay:
1546 case CSSPropertyEmptyCells:
1547 case CSSPropertyFloat:
1548 case CSSPropertyFontStyle:
1549 case CSSPropertyImageRendering:
1550 case CSSPropertyListStylePosition:
1551 case CSSPropertyListStyleType:
1552 case CSSPropertyObjectFit:
1553 case CSSPropertyOutlineStyle:
1554 case CSSPropertyOverflowWrap:
1555 case CSSPropertyOverflowX:
1556 case CSSPropertyOverflowY:
1557 case CSSPropertyPageBreakAfter:
1558 case CSSPropertyPageBreakBefore:
1559 case CSSPropertyPageBreakInside:
1560 case CSSPropertyPointerEvents:
1561 case CSSPropertyPosition:
1562 case CSSPropertyResize:
1563 case CSSPropertySpeak:
1564 case CSSPropertyTableLayout:
1565 case CSSPropertyTextAlignLast:
1566 case CSSPropertyTextJustify:
1567 case CSSPropertyTextLineThroughMode:
1568 case CSSPropertyTextLineThroughStyle:
1569 case CSSPropertyTextOverflow:
1570 case CSSPropertyTextOverlineMode:
1571 case CSSPropertyTextOverlineStyle:
1572 case CSSPropertyTextRendering:
1573 case CSSPropertyTextTransform:
1574 case CSSPropertyTextUnderlineMode:
1575 case CSSPropertyTextUnderlineStyle:
1576 case CSSPropertyTouchActionDelay:
1577 case CSSPropertyVisibility:
1578 case CSSPropertyWebkitAppearance:
1579 case CSSPropertyBackfaceVisibility:
1580 case CSSPropertyWebkitBackfaceVisibility:
1581 case CSSPropertyWebkitBorderAfterStyle:
1582 case CSSPropertyWebkitBorderBeforeStyle:
1583 case CSSPropertyWebkitBorderEndStyle:
1584 case CSSPropertyWebkitBorderFit:
1585 case CSSPropertyWebkitBorderStartStyle:
1586 case CSSPropertyWebkitBoxAlign:
1587 case CSSPropertyWebkitBoxDecorationBreak:
1588 case CSSPropertyWebkitBoxDirection:
1589 case CSSPropertyWebkitBoxLines:
1590 case CSSPropertyWebkitBoxOrient:
1591 case CSSPropertyWebkitBoxPack:
1592 case CSSPropertyInternalCallback:
1593 case CSSPropertyWebkitColumnBreakAfter:
1594 case CSSPropertyWebkitColumnBreakBefore:
1595 case CSSPropertyWebkitColumnBreakInside:
1596 case CSSPropertyColumnFill:
1597 case CSSPropertyWebkitColumnRuleStyle:
1598 case CSSPropertyAlignContent:
1599 case CSSPropertyFlexDirection:
1600 case CSSPropertyFlexWrap:
1601 case CSSPropertyJustifyContent:
1602 case CSSPropertyFontKerning:
1603 case CSSPropertyWebkitFontSmoothing:
1604 case CSSPropertyGridAutoFlow:
1605 case CSSPropertyWebkitLineBreak:
1606 case CSSPropertyWebkitMarginAfterCollapse:
1607 case CSSPropertyWebkitMarginBeforeCollapse:
1608 case CSSPropertyWebkitMarginBottomCollapse:
1609 case CSSPropertyWebkitMarginTopCollapse:
1610 case CSSPropertyInternalMarqueeDirection:
1611 case CSSPropertyInternalMarqueeStyle:
1612 case CSSPropertyWebkitPrintColorAdjust:
1613 case CSSPropertyWebkitRtlOrdering:
1614 case CSSPropertyWebkitRubyPosition:
1615 case CSSPropertyWebkitTextCombine:
1616 case CSSPropertyWebkitTextEmphasisPosition:
1617 case CSSPropertyWebkitTextSecurity:
1618 case CSSPropertyTransformStyle:
1619 case CSSPropertyWebkitTransformStyle:
1620 case CSSPropertyWebkitUserDrag:
1621 case CSSPropertyWebkitUserModify:
1622 case CSSPropertyWebkitUserSelect:
1623 case CSSPropertyWebkitWrapFlow:
1624 case CSSPropertyWebkitWrapThrough:
1625 case CSSPropertyWebkitWritingMode:
1626 case CSSPropertyWhiteSpace:
1627 case CSSPropertyWordBreak:
1628 case CSSPropertyWordWrap:
1629 case CSSPropertyMixBlendMode:
1630 case CSSPropertyIsolation:
1631 // These properties should be handled before in isValidKeywordPropertyAndValue().
1632 ASSERT_NOT_REACHED();
1634 // Properties below are validated inside parseViewportProperty, because we
1635 // check for parser state. We need to invalidate if someone adds them outside
1636 // a @viewport rule.
1637 case CSSPropertyMaxZoom:
1638 case CSSPropertyMinZoom:
1639 case CSSPropertyOrientation:
1640 case CSSPropertyUserZoom:
1641 validPrimitive = false;
1644 return parseSVGValue(propId, important);
1647 if (validPrimitive) {
1648 parsedValue = parseValidPrimitive(id, value);
1649 m_valueList->next();
1651 ASSERT(!m_parsedCalculation);
1653 if (!m_valueList->current() || inShorthand()) {
1654 addProperty(propId, parsedValue.release(), important);
1661 void CSSPropertyParser::addFillValue(RefPtrWillBeRawPtr<CSSValue>& lval, PassRefPtrWillBeRawPtr<CSSValue> rval)
1664 if (lval->isBaseValueList())
1665 toCSSValueList(lval.get())->append(rval);
1667 PassRefPtrWillBeRawPtr<CSSValue> oldlVal(lval.release());
1668 PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
1669 list->append(oldlVal);
1678 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtrWillBeRawPtr<CSSValue>& cssValue)
1680 if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
1681 || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
1682 cssValue = cssValuePool().createIdentifierValue(parserValue->id);
1688 const int cMaxFillProperties = 9;
1690 bool CSSPropertyParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
1692 ASSERT(numProperties <= cMaxFillProperties);
1693 if (numProperties > cMaxFillProperties)
1696 ShorthandScope scope(this, propId);
1698 bool parsedProperty[cMaxFillProperties] = { false };
1699 RefPtrWillBeRawPtr<CSSValue> values[cMaxFillProperties];
1701 // Zero initialize the array of raw pointers.
1702 memset(&values, 0, sizeof(values));
1704 RefPtrWillBeRawPtr<CSSValue> clipValue = nullptr;
1705 RefPtrWillBeRawPtr<CSSValue> positionYValue = nullptr;
1706 RefPtrWillBeRawPtr<CSSValue> repeatYValue = nullptr;
1707 bool foundClip = false;
1709 bool foundPositionCSSProperty = false;
1711 while (m_valueList->current()) {
1712 CSSParserValue* val = m_valueList->current();
1713 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
1714 // We hit the end. Fill in all remaining values with the initial value.
1715 m_valueList->next();
1716 for (i = 0; i < numProperties; ++i) {
1717 if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
1718 // Color is not allowed except as the last item in a list for backgrounds.
1719 // Reject the entire property.
1722 if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
1723 addFillValue(values[i], cssValuePool().createImplicitInitialValue());
1724 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1725 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
1726 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1727 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
1728 if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
1729 // If background-origin wasn't present, then reset background-clip also.
1730 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
1733 parsedProperty[i] = false;
1735 if (!m_valueList->current())
1739 bool sizeCSSPropertyExpected = false;
1740 if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
1741 sizeCSSPropertyExpected = true;
1742 m_valueList->next();
1745 foundPositionCSSProperty = false;
1747 for (i = 0; !found && i < numProperties; ++i) {
1749 if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgroundSize && properties[i] != CSSPropertyWebkitMaskSize))
1751 if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgroundSize || properties[i] == CSSPropertyWebkitMaskSize))
1754 if (!parsedProperty[i]) {
1755 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
1756 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
1757 CSSPropertyID propId1, propId2;
1758 CSSParserValue* parserValue = m_valueList->current();
1759 // parseFillProperty() may modify m_implicitShorthand, so we MUST reset it
1760 // before EACH return below.
1761 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
1762 parsedProperty[i] = found = true;
1763 addFillValue(values[i], val1.release());
1764 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1765 addFillValue(positionYValue, val2.release());
1766 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1767 addFillValue(repeatYValue, val2.release());
1768 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
1769 // Reparse the value as a clip, and see if we succeed.
1770 if (parseBackgroundClip(parserValue, val1))
1771 addFillValue(clipValue, val1.release()); // The property parsed successfully.
1773 addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
1775 if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
1777 addFillValue(clipValue, val1.release());
1780 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1781 foundPositionCSSProperty = true;
1786 // if we didn't find at least one match, this is an
1787 // invalid shorthand and we have to ignore it
1789 m_implicitShorthand = false;
1794 // Now add all of the properties we found.
1795 for (i = 0; i < numProperties; i++) {
1796 // Fill in any remaining properties with the initial value.
1797 if (!parsedProperty[i]) {
1798 addFillValue(values[i], cssValuePool().createImplicitInitialValue());
1799 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1800 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
1801 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1802 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
1803 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
1804 // If background-origin wasn't present, then reset background-clip also.
1805 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
1808 if (properties[i] == CSSPropertyBackgroundPosition) {
1809 addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
1810 // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
1811 addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
1812 } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
1813 addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
1814 // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
1815 addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
1816 } else if (properties[i] == CSSPropertyBackgroundRepeat) {
1817 addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
1818 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
1819 addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
1820 } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
1821 addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
1822 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
1823 addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
1824 } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
1825 // Value is already set while updating origin
1827 else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i] && m_context.useLegacyBackgroundSizeShorthandBehavior())
1830 addProperty(properties[i], values[i].release(), important);
1832 // Add in clip values when we hit the corresponding origin property.
1833 if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
1834 addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
1835 else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
1836 addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
1839 m_implicitShorthand = false;
1843 void CSSPropertyParser::addAnimationValue(RefPtrWillBeRawPtr<CSSValue>& lval, PassRefPtrWillBeRawPtr<CSSValue> rval)
1846 if (lval->isValueList())
1847 toCSSValueList(lval.get())->append(rval);
1849 PassRefPtrWillBeRawPtr<CSSValue> oldVal(lval.release());
1850 PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
1851 list->append(oldVal);
1860 bool CSSPropertyParser::parseAnimationShorthand(CSSPropertyID propId, bool important)
1862 const StylePropertyShorthand& animationProperties = parsingShorthandForProperty(propId);
1863 const unsigned numProperties = 8;
1865 // The list of properties in the shorthand should be the same
1866 // length as the list with animation name in last position, even though they are
1867 // in a different order.
1868 ASSERT(numProperties == animationProperties.length());
1869 ASSERT(numProperties == shorthandForProperty(propId).length());
1871 ShorthandScope scope(this, propId);
1873 bool parsedProperty[numProperties] = { false };
1874 AnimationParseContext context;
1875 RefPtrWillBeRawPtr<CSSValue> values[numProperties];
1877 // Zero initialize the array of raw pointers.
1878 memset(&values, 0, sizeof(values));
1882 while (m_valueList->current()) {
1883 CSSParserValue* val = m_valueList->current();
1884 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
1885 // We hit the end. Fill in all remaining values with the initial value.
1886 m_valueList->next();
1887 for (i = 0; i < numProperties; ++i) {
1888 if (!parsedProperty[i])
1889 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
1890 parsedProperty[i] = false;
1892 if (!m_valueList->current())
1894 context.commitFirstAnimation();
1898 for (i = 0; i < numProperties; ++i) {
1899 if (!parsedProperty[i]) {
1900 RefPtrWillBeRawPtr<CSSValue> val = nullptr;
1901 if (parseAnimationProperty(animationProperties.properties()[i], val, context)) {
1902 parsedProperty[i] = found = true;
1903 addAnimationValue(values[i], val.release());
1909 // if we didn't find at least one match, this is an
1910 // invalid shorthand and we have to ignore it
1915 for (i = 0; i < numProperties; ++i) {
1916 // If we didn't find the property, set an intial value.
1917 if (!parsedProperty[i])
1918 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
1920 if (RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
1921 addPropertyWithPrefixingVariant(animationProperties.properties()[i], values[i].release(), important);
1923 addProperty(animationProperties.properties()[i], values[i].release(), important);
1929 bool CSSPropertyParser::parseTransitionShorthand(CSSPropertyID propId, bool important)
1931 const unsigned numProperties = 4;
1932 const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
1933 ASSERT(numProperties == shorthand.length());
1935 ShorthandScope scope(this, propId);
1937 bool parsedProperty[numProperties] = { false };
1938 AnimationParseContext context;
1939 RefPtrWillBeRawPtr<CSSValue> values[numProperties];
1941 // Zero initialize the array of raw pointers.
1942 memset(&values, 0, sizeof(values));
1946 while (m_valueList->current()) {
1947 CSSParserValue* val = m_valueList->current();
1948 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
1949 // We hit the end. Fill in all remaining values with the initial value.
1950 m_valueList->next();
1951 for (i = 0; i < numProperties; ++i) {
1952 if (!parsedProperty[i])
1953 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
1954 parsedProperty[i] = false;
1956 if (!m_valueList->current())
1958 context.commitFirstAnimation();
1962 for (i = 0; !found && i < numProperties; ++i) {
1963 if (!parsedProperty[i]) {
1964 RefPtrWillBeRawPtr<CSSValue> val = nullptr;
1965 if (parseAnimationProperty(shorthand.properties()[i], val, context)) {
1966 parsedProperty[i] = found = true;
1967 addAnimationValue(values[i], val.release());
1970 // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid.
1971 if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation())
1976 // if we didn't find at least one match, this is an
1977 // invalid shorthand and we have to ignore it
1982 // Fill in any remaining properties with the initial value.
1983 for (i = 0; i < numProperties; ++i) {
1984 if (!parsedProperty[i])
1985 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
1988 // Now add all of the properties we found.
1989 for (i = 0; i < numProperties; i++)
1990 addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].release(), important);
1995 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnWidth()
1997 CSSParserValue* value = m_valueList->current();
1998 // Always parse lengths in strict mode here, since it would be ambiguous otherwise when used in
1999 // the 'columns' shorthand property.
2000 if (value->id == CSSValueAuto
2001 || (validUnit(value, FLength | FNonNeg, HTMLStandardMode) && value->fValue)) {
2002 RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
2003 m_valueList->next();
2009 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnCount()
2011 CSSParserValue* value = m_valueList->current();
2012 if (value->id == CSSValueAuto
2013 || (!value->id && validUnit(value, FPositiveInteger, HTMLQuirksMode))) {
2014 RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
2015 m_valueList->next();
2021 bool CSSPropertyParser::parseColumnsShorthand(bool important)
2023 RefPtrWillBeRawPtr<CSSValue> columnWidth = nullptr;
2024 RefPtrWillBeRawPtr<CSSValue> columnCount = nullptr;
2025 bool hasPendingExplicitAuto = false;
2027 for (unsigned propertiesParsed = 0; CSSParserValue* value = m_valueList->current(); propertiesParsed++) {
2028 if (propertiesParsed >= 2)
2029 return false; // Too many values for this shorthand. Invalid declaration.
2030 if (!propertiesParsed && value->id == CSSValueAuto) {
2031 // 'auto' is a valid value for any of the two longhands, and at this point we
2032 // don't know which one(s) it is meant for. We need to see if there are other
2034 m_valueList->next();
2035 hasPendingExplicitAuto = true;
2038 if ((columnWidth = parseColumnWidth()))
2042 if ((columnCount = parseColumnCount()))
2045 // If we didn't find at least one match, this is an
2046 // invalid shorthand and we have to ignore it.
2050 if (hasPendingExplicitAuto) {
2051 // Time to assign the previously skipped 'auto' value to a property. If both properties are
2052 // unassigned at this point (i.e. 'columns:auto'), it doesn't matter that much which one we
2053 // set (although it does make a slight difference to web-inspector). The one we don't set
2054 // here will get an implicit 'auto' value further down.
2056 columnWidth = cssValuePool().createIdentifierValue(CSSValueAuto);
2058 ASSERT(!columnCount);
2059 columnCount = cssValuePool().createIdentifierValue(CSSValueAuto);
2062 ASSERT(columnCount || columnWidth);
2064 // Any unassigned property at this point will become implicit 'auto'.
2066 addProperty(CSSPropertyWebkitColumnWidth, columnWidth, important);
2068 addProperty(CSSPropertyWebkitColumnWidth, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
2070 addProperty(CSSPropertyWebkitColumnCount, columnCount, important);
2072 addProperty(CSSPropertyWebkitColumnCount, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
2076 bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
2078 // We try to match as many properties as possible
2079 // We set up an array of booleans to mark which property has been found,
2080 // and we try to search for properties until it makes no longer any sense.
2081 ShorthandScope scope(this, propId);
2084 unsigned propertiesParsed = 0;
2085 bool propertyFound[6] = { false, false, false, false, false, false }; // 6 is enough size.
2087 while (m_valueList->current()) {
2089 for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
2090 if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
2091 propertyFound[propIndex] = found = true;
2096 // if we didn't find at least one match, this is an
2097 // invalid shorthand and we have to ignore it
2102 if (propertiesParsed == shorthand.length())
2105 // Fill in any remaining properties with the initial value.
2106 ImplicitScope implicitScope(this, PropertyImplicit);
2107 const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization();
2108 for (unsigned i = 0; i < shorthand.length(); ++i) {
2109 if (propertyFound[i])
2112 if (propertiesForInitialization) {
2113 const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]);
2114 for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
2115 addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
2117 addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
2123 bool CSSPropertyParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties, bool important)
2125 /* From the CSS 2 specs, 8.3
2126 * If there is only one value, it applies to all sides. If there are two values, the top and
2127 * bottom margins are set to the first value and the right and left margins are set to the second.
2128 * If there are three values, the top is set to the first value, the left and right are set to the
2129 * second, and the bottom is set to the third. If there are four values, they apply to the top,
2130 * right, bottom, and left, respectively.
2133 int num = inShorthand() ? 1 : m_valueList->size();
2135 ShorthandScope scope(this, propId);
2137 // the order is top, right, bottom, left
2140 if (!parseValue(properties[0], important))
2142 CSSValue* value = m_parsedProperties.last().value();
2143 ImplicitScope implicitScope(this, PropertyImplicit);
2144 addProperty(properties[1], value, important);
2145 addProperty(properties[2], value, important);
2146 addProperty(properties[3], value, important);
2150 if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
2152 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
2153 ImplicitScope implicitScope(this, PropertyImplicit);
2154 addProperty(properties[2], value, important);
2155 value = m_parsedProperties[m_parsedProperties.size() - 2].value();
2156 addProperty(properties[3], value, important);
2160 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
2162 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
2163 ImplicitScope implicitScope(this, PropertyImplicit);
2164 addProperty(properties[3], value, important);
2168 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
2169 !parseValue(properties[2], important) || !parseValue(properties[3], important))
2181 // auto | <identifier>
2182 bool CSSPropertyParser::parsePage(CSSPropertyID propId, bool important)
2184 ASSERT(propId == CSSPropertyPage);
2186 if (m_valueList->size() != 1)
2189 CSSParserValue* value = m_valueList->current();
2193 if (value->id == CSSValueAuto) {
2194 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
2196 } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
2197 addProperty(propId, createPrimitiveStringValue(value), important);
2203 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
2204 bool CSSPropertyParser::parseSize(CSSPropertyID propId, bool important)
2206 ASSERT(propId == CSSPropertySize);
2208 if (m_valueList->size() > 2)
2211 CSSParserValue* value = m_valueList->current();
2215 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
2218 SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
2219 if (paramType == None)
2222 // Second parameter, if any.
2223 value = m_valueList->next();
2225 paramType = parseSizeParameter(parsedValues.get(), value, paramType);
2226 if (paramType == None)
2230 addProperty(propId, parsedValues.release(), important);
2234 CSSPropertyParser::SizeParameterType CSSPropertyParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
2236 switch (value->id) {
2238 if (prevParamType == None) {
2239 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
2243 case CSSValueLandscape:
2244 case CSSValuePortrait:
2245 if (prevParamType == None || prevParamType == PageSize) {
2246 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
2255 case CSSValueLedger:
2257 case CSSValueLetter:
2258 if (prevParamType == None || prevParamType == Orientation) {
2259 // Normalize to Page Size then Orientation order by prepending.
2260 // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
2261 parsedValues->prepend(cssValuePool().createIdentifierValue(value->id));
2266 if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) {
2267 parsedValues->append(createPrimitiveNumericValue(value));
2276 // [ <string> <string> ]+ | inherit | none
2277 // inherit and none are handled in parseValue.
2278 bool CSSPropertyParser::parseQuotes(CSSPropertyID propId, bool important)
2280 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
2281 while (CSSParserValue* val = m_valueList->current()) {
2282 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
2283 if (val->unit == CSSPrimitiveValue::CSS_STRING)
2284 parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
2287 values->append(parsedValue.release());
2288 m_valueList->next();
2290 if (values->length()) {
2291 addProperty(propId, values.release(), important);
2292 m_valueList->next();
2298 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
2299 // in CSS 2.1 this got somewhat reduced:
2300 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
2301 bool CSSPropertyParser::parseContent(CSSPropertyID propId, bool important)
2303 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
2305 while (CSSParserValue* val = m_valueList->current()) {
2306 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
2307 if (val->unit == CSSPrimitiveValue::CSS_URI) {
2309 parsedValue = createCSSImageValueWithReferrer(val->string, completeURL(val->string));
2310 } else if (val->unit == CSSParserValue::Function) {
2311 // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
2312 CSSParserValueList* args = val->function->args.get();
2315 if (equalIgnoringCase(val->function->name, "attr(")) {
2316 parsedValue = parseAttr(args);
2319 } else if (equalIgnoringCase(val->function->name, "counter(")) {
2320 parsedValue = parseCounterContent(args, false);
2323 } else if (equalIgnoringCase(val->function->name, "counters(")) {
2324 parsedValue = parseCounterContent(args, true);
2327 } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
2328 parsedValue = parseImageSet(m_valueList.get());
2331 } else if (isGeneratedImageValue(val)) {
2332 if (!parseGeneratedImage(m_valueList.get(), parsedValue))
2336 } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
2342 // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
2346 case CSSValueOpenQuote:
2347 case CSSValueCloseQuote:
2348 case CSSValueNoOpenQuote:
2349 case CSSValueNoCloseQuote:
2351 case CSSValueNormal:
2352 parsedValue = cssValuePool().createIdentifierValue(val->id);
2356 } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
2357 parsedValue = createPrimitiveStringValue(val);
2361 values->append(parsedValue.release());
2362 m_valueList->next();
2365 if (values->length()) {
2366 addProperty(propId, values.release(), important);
2367 m_valueList->next();
2374 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAttr(CSSParserValueList* args)
2376 if (args->size() != 1)
2379 CSSParserValue* a = args->current();
2381 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
2384 String attrName = a->string;
2385 // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
2386 // But HTML attribute names can't have those characters, and we should not
2387 // even parse them inside attr().
2388 if (attrName[0] == '-')
2391 if (m_context.isHTMLDocument())
2392 attrName = attrName.lower();
2394 return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
2397 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBackgroundColor()
2399 CSSValueID id = m_valueList->current()->id;
2400 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
2401 (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
2402 return cssValuePool().createIdentifierValue(id);
2403 return parseColor();
2406 bool CSSPropertyParser::parseFillImage(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value)
2408 if (valueList->current()->id == CSSValueNone) {
2409 value = cssValuePool().createIdentifierValue(CSSValueNone);
2412 if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
2413 value = createCSSImageValueWithReferrer(valueList->current()->string, completeURL(valueList->current()->string));
2417 if (isGeneratedImageValue(valueList->current()))
2418 return parseGeneratedImage(valueList, value);
2420 if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) {
2421 value = parseImageSet(m_valueList.get());
2429 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionX(CSSParserValueList* valueList)
2431 int id = valueList->current()->id;
2432 if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
2434 if (id == CSSValueRight)
2436 else if (id == CSSValueCenter)
2438 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2440 if (validUnit(valueList->current(), FPercent | FLength))
2441 return createPrimitiveNumericValue(valueList->current());
2445 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionY(CSSParserValueList* valueList)
2447 int id = valueList->current()->id;
2448 if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
2450 if (id == CSSValueBottom)
2452 else if (id == CSSValueCenter)
2454 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2456 if (validUnit(valueList->current(), FPercent | FLength))
2457 return createPrimitiveNumericValue(valueList->current());
2461 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode)
2463 CSSValueID id = valueList->current()->id;
2464 if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
2466 if (id == CSSValueLeft || id == CSSValueRight) {
2467 if (cumulativeFlags & XFillPosition)
2469 cumulativeFlags |= XFillPosition;
2470 individualFlag = XFillPosition;
2471 if (id == CSSValueRight)
2474 else if (id == CSSValueTop || id == CSSValueBottom) {
2475 if (cumulativeFlags & YFillPosition)
2477 cumulativeFlags |= YFillPosition;
2478 individualFlag = YFillPosition;
2479 if (id == CSSValueBottom)
2481 } else if (id == CSSValueCenter) {
2482 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
2484 cumulativeFlags |= AmbiguousFillPosition;
2485 individualFlag = AmbiguousFillPosition;
2488 if (parsingMode == ResolveValuesAsKeyword)
2489 return cssValuePool().createIdentifierValue(id);
2491 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2493 if (validUnit(valueList->current(), FPercent | FLength)) {
2494 if (!cumulativeFlags) {
2495 cumulativeFlags |= XFillPosition;
2496 individualFlag = XFillPosition;
2497 } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
2498 cumulativeFlags |= YFillPosition;
2499 individualFlag = YFillPosition;
2501 if (m_parsedCalculation)
2502 m_parsedCalculation.release();
2505 return createPrimitiveNumericValue(valueList->current());
2510 static bool isValueConflictingWithCurrentEdge(int value1, int value2)
2512 if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSValueLeft || value2 == CSSValueRight))
2515 if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSValueTop || value2 == CSSValueBottom))
2521 static bool isFillPositionKeyword(CSSValueID value)
2523 return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter;
2526 void CSSPropertyParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2)
2528 // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <percentage> | <length> ]
2529 // In the case of 4 values <position> requires the second value to be a length or a percentage.
2530 if (isFillPositionKeyword(parsedValue2->getValueID()))
2533 unsigned cumulativeFlags = 0;
2534 FillPositionFlag value3Flag = InvalidFillPosition;
2535 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
2539 CSSValueID ident1 = parsedValue1->getValueID();
2540 CSSValueID ident3 = value3->getValueID();
2542 if (ident1 == CSSValueCenter)
2545 if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
2548 // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
2549 // needed as the second call to parseFillPositionComponent was on purpose not checking it. In the
2550 // case of two values top 20px is invalid but in the case of 4 values it becomes valid.
2551 if (isValueConflictingWithCurrentEdge(ident1, ident3))
2556 cumulativeFlags = 0;
2557 FillPositionFlag value4Flag = InvalidFillPosition;
2558 RefPtrWillBeRawPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(valueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
2562 // 4th value must be a length or a percentage.
2563 if (isFillPositionKeyword(value4->getValueID()))
2566 value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
2567 value2 = createPrimitiveValuePair(value3, value4);
2569 if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
2570 value1.swap(value2);
2574 void CSSPropertyParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2)
2576 unsigned cumulativeFlags = 0;
2577 FillPositionFlag value3Flag = InvalidFillPosition;
2578 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
2580 // value3 is not an expected value, we return.
2586 bool swapNeeded = false;
2587 CSSValueID ident1 = parsedValue1->getValueID();
2588 CSSValueID ident2 = parsedValue2->getValueID();
2589 CSSValueID ident3 = value3->getValueID();
2591 CSSValueID firstPositionKeyword;
2592 CSSValueID secondPositionKeyword;
2594 if (ident1 == CSSValueCenter) {
2595 // <position> requires the first 'center' to be followed by a keyword.
2596 if (!isFillPositionKeyword(ident2))
2599 // If 'center' is the first keyword then the last one needs to be a length.
2600 if (isFillPositionKeyword(ident3))
2603 firstPositionKeyword = CSSValueLeft;
2604 if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
2605 firstPositionKeyword = CSSValueTop;
2608 value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
2609 value2 = createPrimitiveValuePair(parsedValue2, value3);
2610 } else if (ident3 == CSSValueCenter) {
2611 if (isFillPositionKeyword(ident2))
2614 secondPositionKeyword = CSSValueTop;
2615 if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
2616 secondPositionKeyword = CSSValueLeft;
2619 value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
2620 value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
2622 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstPositionValue = nullptr;
2623 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondPositionValue = nullptr;
2625 if (isFillPositionKeyword(ident2)) {
2626 // To match CSS grammar, we should only accept: [ center | left | right | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ].
2627 ASSERT(ident2 != CSSValueCenter);
2629 if (isFillPositionKeyword(ident3))
2632 secondPositionValue = value3;
2633 secondPositionKeyword = ident2;
2634 firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
2636 // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
2637 if (!isFillPositionKeyword(ident3))
2640 firstPositionValue = parsedValue2;
2641 secondPositionKeyword = ident3;
2642 secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
2645 if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
2648 value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue);
2649 value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue);
2652 if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
2653 value1.swap(value2);
2656 CSSPrimitiveValue* first = toCSSPrimitiveValue(value1.get());
2657 CSSPrimitiveValue* second = toCSSPrimitiveValue(value2.get());
2658 ident1 = first->getPairValue()->first()->getValueID();
2659 ident2 = second->getPairValue()->first()->getValueID();
2660 ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
2661 ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
2665 inline bool CSSPropertyParser::isPotentialPositionValue(CSSParserValue* value)
2667 return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue);
2670 void CSSPropertyParser::parseFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
2672 unsigned numberOfValues = 0;
2673 for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++numberOfValues) {
2674 CSSParserValue* current = valueList->valueAt(i);
2675 if (isComma(current) || !current || isForwardSlashOperator(current) || !isPotentialPositionValue(current))
2679 if (numberOfValues > 4)
2682 // If we are parsing two values, we can safely call the CSS 2.1 parsing function and return.
2683 if (numberOfValues <= 2) {
2684 parse2ValuesFillPosition(valueList, value1, value2);
2688 ASSERT(numberOfValues > 2 && numberOfValues <= 4);
2690 CSSParserValue* value = valueList->current();
2692 // <position> requires the first value to be a background keyword.
2693 if (!isFillPositionKeyword(value->id))
2696 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
2697 unsigned cumulativeFlags = 0;
2698 FillPositionFlag value1Flag = InvalidFillPosition;
2699 FillPositionFlag value2Flag = InvalidFillPosition;
2700 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
2706 // In case we are parsing more than two values, relax the check inside of parseFillPositionComponent. top 20px is
2707 // a valid start for <position>.
2708 cumulativeFlags = AmbiguousFillPosition;
2709 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
2717 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(value1.get());
2718 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(value2.get());
2723 // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
2724 if (parsedValue2->getValueID() == CSSValueCenter)
2727 if (numberOfValues == 3)
2728 parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
2730 parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
2733 void CSSPropertyParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
2735 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
2736 unsigned cumulativeFlags = 0;
2737 FillPositionFlag value1Flag = InvalidFillPosition;
2738 FillPositionFlag value2Flag = InvalidFillPosition;
2739 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
2743 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
2744 // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the
2745 // value was explicitly specified for our property.
2746 CSSParserValue* value = valueList->next();
2748 // First check for the comma. If so, we are finished parsing this value or value pair.
2753 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
2757 if (!inShorthand()) {
2765 // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
2766 // is simply 50%. This is our default.
2767 // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
2768 // For left/right/center, the default of 50% in the y is still correct.
2769 value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
2771 if (value1Flag == YFillPosition || value2Flag == XFillPosition)
2772 value1.swap(value2);
2775 void CSSPropertyParser::parseFillRepeat(RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
2777 CSSValueID id = m_valueList->current()->id;
2778 if (id == CSSValueRepeatX) {
2779 m_implicitShorthand = true;
2780 value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
2781 value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
2782 m_valueList->next();
2785 if (id == CSSValueRepeatY) {
2786 m_implicitShorthand = true;
2787 value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
2788 value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
2789 m_valueList->next();
2792 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
2793 value1 = cssValuePool().createIdentifierValue(id);
2799 CSSParserValue* value = m_valueList->next();
2801 // Parse the second value if one is available
2802 if (value && !isComma(value)) {
2804 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
2805 value2 = cssValuePool().createIdentifierValue(id);
2806 m_valueList->next();
2811 // If only one value was specified, value2 is the same as value1.
2812 m_implicitShorthand = true;
2813 value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get())->getValueID());
2816 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
2819 CSSParserValue* value = m_valueList->current();
2821 if (value->id == CSSValueContain || value->id == CSSValueCover)
2822 return cssValuePool().createIdentifierValue(value->id);
2824 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = nullptr;
2826 if (value->id == CSSValueAuto)
2827 parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
2829 if (!validUnit(value, FLength | FPercent))
2831 parsedValue1 = createPrimitiveNumericValue(value);
2834 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr;
2835 if ((value = m_valueList->next())) {
2836 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
2838 else if (value->id != CSSValueAuto) {
2839 if (!validUnit(value, FLength | FPercent)) {
2842 // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
2843 m_valueList->previous();
2845 parsedValue2 = createPrimitiveNumericValue(value);
2847 } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
2848 // For backwards compatibility we set the second value to the first if it is omitted.
2849 // We only need to do this for -webkit-background-size. It should be safe to let masks match
2850 // the real property.
2851 parsedValue2 = parsedValue1;
2855 return parsedValue1;
2857 Pair::IdenticalValuesPolicy policy = propId == CSSPropertyWebkitBackgroundSize ?
2858 Pair::DropIdenticalValues : Pair::KeepIdenticalValues;
2860 return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release(), policy);
2863 bool CSSPropertyParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
2864 RefPtrWillBeRawPtr<CSSValue>& retValue1, RefPtrWillBeRawPtr<CSSValue>& retValue2)
2866 RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
2867 RefPtrWillBeRawPtr<CSSValueList> values2 = nullptr;
2868 CSSParserValue* val;
2869 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
2870 RefPtrWillBeRawPtr<CSSValue> value2 = nullptr;
2872 bool allowComma = false;
2874 retValue1 = retValue2 = nullptr;
2877 if (propId == CSSPropertyBackgroundPosition) {
2878 propId1 = CSSPropertyBackgroundPositionX;
2879 propId2 = CSSPropertyBackgroundPositionY;
2880 } else if (propId == CSSPropertyWebkitMaskPosition) {
2881 propId1 = CSSPropertyWebkitMaskPositionX;
2882 propId2 = CSSPropertyWebkitMaskPositionY;
2883 } else if (propId == CSSPropertyBackgroundRepeat) {
2884 propId1 = CSSPropertyBackgroundRepeatX;
2885 propId2 = CSSPropertyBackgroundRepeatY;
2886 } else if (propId == CSSPropertyWebkitMaskRepeat) {
2887 propId1 = CSSPropertyWebkitMaskRepeatX;
2888 propId2 = CSSPropertyWebkitMaskRepeatY;
2891 while ((val = m_valueList->current())) {
2892 RefPtrWillBeRawPtr<CSSValue> currValue = nullptr;
2893 RefPtrWillBeRawPtr<CSSValue> currValue2 = nullptr;
2898 m_valueList->next();
2903 case CSSPropertyBackgroundColor:
2904 currValue = parseBackgroundColor();
2906 m_valueList->next();
2908 case CSSPropertyBackgroundAttachment:
2909 if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
2910 currValue = cssValuePool().createIdentifierValue(val->id);
2911 m_valueList->next();
2914 case CSSPropertyBackgroundImage:
2915 case CSSPropertyWebkitMaskImage:
2916 if (parseFillImage(m_valueList.get(), currValue))
2917 m_valueList->next();
2919 case CSSPropertyWebkitBackgroundClip:
2920 case CSSPropertyWebkitBackgroundOrigin:
2921 case CSSPropertyWebkitMaskClip:
2922 case CSSPropertyWebkitMaskOrigin:
2923 // The first three values here are deprecated and do not apply to the version of the property that has
2924 // the -webkit- prefix removed.
2925 if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
2926 val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
2927 ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
2928 (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
2929 currValue = cssValuePool().createIdentifierValue(val->id);
2930 m_valueList->next();
2933 case CSSPropertyBackgroundClip:
2934 if (parseBackgroundClip(val, currValue))
2935 m_valueList->next();
2937 case CSSPropertyBackgroundOrigin:
2938 if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
2939 currValue = cssValuePool().createIdentifierValue(val->id);
2940 m_valueList->next();
2943 case CSSPropertyBackgroundPosition:
2944 case CSSPropertyWebkitMaskPosition:
2945 parseFillPosition(m_valueList.get(), currValue, currValue2);
2946 // parseFillPosition advances the m_valueList pointer.
2948 case CSSPropertyBackgroundPositionX:
2949 case CSSPropertyWebkitMaskPositionX: {
2950 currValue = parseFillPositionX(m_valueList.get());
2952 m_valueList->next();
2955 case CSSPropertyBackgroundPositionY:
2956 case CSSPropertyWebkitMaskPositionY: {
2957 currValue = parseFillPositionY(m_valueList.get());
2959 m_valueList->next();
2962 case CSSPropertyWebkitBackgroundComposite:
2963 case CSSPropertyWebkitMaskComposite:
2964 if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) {
2965 currValue = cssValuePool().createIdentifierValue(val->id);
2966 m_valueList->next();
2969 case CSSPropertyBackgroundBlendMode:
2970 if (val->id == CSSValueNormal || val->id == CSSValueMultiply
2971 || val->id == CSSValueScreen || val->id == CSSValueOverlay || val->id == CSSValueDarken
2972 || val->id == CSSValueLighten || val->id == CSSValueColorDodge || val->id == CSSValueColorBurn
2973 || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference
2974 || val->id == CSSValueExclusion || val->id == CSSValueHue || val->id == CSSValueSaturation
2975 || val->id == CSSValueColor || val->id == CSSValueLuminosity) {
2976 currValue = cssValuePool().createIdentifierValue(val->id);
2977 m_valueList->next();
2980 case CSSPropertyBackgroundRepeat:
2981 case CSSPropertyWebkitMaskRepeat:
2982 parseFillRepeat(currValue, currValue2);
2983 // parseFillRepeat advances the m_valueList pointer
2985 case CSSPropertyBackgroundSize:
2986 case CSSPropertyWebkitBackgroundSize:
2987 case CSSPropertyWebkitMaskSize: {
2988 currValue = parseFillSize(propId, allowComma);
2990 m_valueList->next();
2993 case CSSPropertyMaskSourceType: {
2994 if (RuntimeEnabledFeatures::cssMaskSourceTypeEnabled()) {
2995 if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id == CSSValueLuminance) {
2996 currValue = cssValuePool().createIdentifierValue(val->id);
2997 m_valueList->next();
2999 currValue = nullptr;
3010 if (value && !values) {
3011 values = CSSValueList::createCommaSeparated();
3012 values->append(value.release());
3015 if (value2 && !values2) {
3016 values2 = CSSValueList::createCommaSeparated();
3017 values2->append(value2.release());
3021 values->append(currValue.release());
3023 value = currValue.release();
3026 values2->append(currValue2.release());
3028 value2 = currValue2.release();
3032 // When parsing any fill shorthand property, we let it handle building up the lists for all
3038 if (values && values->length()) {
3039 retValue1 = values.release();
3040 if (values2 && values2->length())
3041 retValue2 = values2.release();
3045 retValue1 = value.release();
3046 retValue2 = value2.release();
3052 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDelay()
3054 CSSParserValue* value = m_valueList->current();
3055 if (validUnit(value, FTime))
3056 return createPrimitiveNumericValue(value);
3060 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDirection()
3062 CSSParserValue* value = m_valueList->current();
3063 if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
3064 return cssValuePool().createIdentifierValue(value->id);
3068 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDuration()
3070 CSSParserValue* value = m_valueList->current();
3071 if (validUnit(value, FTime | FNonNeg))
3072 return createPrimitiveNumericValue(value);
3076 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationFillMode()
3078 CSSParserValue* value = m_valueList->current();
3079 if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
3080 return cssValuePool().createIdentifierValue(value->id);
3084 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationIterationCount()
3086 CSSParserValue* value = m_valueList->current();
3087 if (value->id == CSSValueInfinite)
3088 return cssValuePool().createIdentifierValue(value->id);
3089 if (validUnit(value, FNumber | FNonNeg))
3090 return createPrimitiveNumericValue(value);
3094 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationName()
3096 CSSParserValue* value = m_valueList->current();
3097 if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
3098 if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value, "none"))) {
3099 return cssValuePool().createIdentifierValue(CSSValueNone);
3101 return createPrimitiveStringValue(value);
3107 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationPlayState()
3109 CSSParserValue* value = m_valueList->current();
3110 if (value->id == CSSValueRunning || value->id == CSSValuePaused)
3111 return cssValuePool().createIdentifierValue(value->id);
3115 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationProperty(AnimationParseContext& context)
3117 CSSParserValue* value = m_valueList->current();
3118 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
3120 CSSPropertyID result = cssPropertyID(value->string);
3121 if (result && RuntimeCSSEnabled::isCSSPropertyEnabled(result))
3122 return cssValuePool().createIdentifierValue(result);
3123 if (equalIgnoringCase(value, "all"))
3124 return cssValuePool().createIdentifierValue(CSSValueAll);
3125 if (equalIgnoringCase(value, "none")) {
3126 context.commitAnimationPropertyKeyword();
3127 return cssValuePool().createIdentifierValue(CSSValueNone);
3132 bool CSSPropertyParser::parseWebkitTransformOriginShorthand(RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, RefPtrWillBeRawPtr<CSSValue>& value3)
3134 parse2ValuesFillPosition(m_valueList.get(), value1, value2);
3137 if (m_valueList->current()) {
3138 if (validUnit(m_valueList->current(), FLength)) {
3139 value3 = createPrimitiveNumericValue(m_valueList->current());
3140 m_valueList->next();
3145 value3 = cssValuePool().createImplicitInitialValue();
3149 bool CSSPropertyParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
3151 CSSParserValue* v = args->current();
3152 if (!validUnit(v, FNumber))
3157 // The last number in the function has no comma after it, so we're done.
3165 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationTimingFunction()
3167 CSSParserValue* value = m_valueList->current();
3168 if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
3169 || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd
3170 || (value->id == CSSValueStepMiddle && RuntimeEnabledFeatures::webAnimationsElementAnimateEnabled()))
3171 return cssValuePool().createIdentifierValue(value->id);
3173 // We must be a function.
3174 if (value->unit != CSSParserValue::Function)
3177 CSSParserValueList* args = value->function->args.get();
3179 if (equalIgnoringCase(value->function->name, "steps(")) {
3180 // For steps, 1 or 2 params must be specified (comma-separated)
3181 if (!args || (args->size() != 1 && args->size() != 3))
3184 // There are two values.
3186 StepsTimingFunction::StepAtPosition stepAtPosition = StepsTimingFunction::StepAtEnd;
3188 CSSParserValue* v = args->current();
3189 if (!validUnit(v, FInteger))
3191 numSteps = clampToInteger(v->fValue);
3197 // There is a comma so we need to parse the second value
3202 case CSSValueMiddle:
3203 if (!RuntimeEnabledFeatures::webAnimationsAPIEnabled())
3205 stepAtPosition = StepsTimingFunction::StepAtMiddle;
3208 stepAtPosition = StepsTimingFunction::StepAtStart;
3211 stepAtPosition = StepsTimingFunction::StepAtEnd;
3218 return CSSStepsTimingFunctionValue::create(numSteps, stepAtPosition);
3221 if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
3222 // For cubic bezier, 4 values must be specified.
3223 if (!args || args->size() != 7)
3226 // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range.
3227 double x1, y1, x2, y2;
3229 if (!parseCubicBezierTimingFunctionValue(args, x1))
3231 if (x1 < 0 || x1 > 1)
3233 if (!parseCubicBezierTimingFunctionValue(args, y1))
3235 if (!parseCubicBezierTimingFunctionValue(args, x2))
3237 if (x2 < 0 || x2 > 1)
3239 if (!parseCubicBezierTimingFunctionValue(args, y2))
3242 return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
3248 bool CSSPropertyParser::parseAnimationProperty(CSSPropertyID propId, RefPtrWillBeRawPtr<CSSValue>& result, AnimationParseContext& context)
3250 RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
3251 CSSParserValue* val;
3252 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
3253 bool allowComma = false;
3257 while ((val = m_valueList->current())) {
3258 RefPtrWillBeRawPtr<CSSValue> currValue = nullptr;
3262 m_valueList->next();
3267 case CSSPropertyAnimationDelay:
3268 case CSSPropertyWebkitAnimationDelay:
3269 case CSSPropertyTransitionDelay:
3270 case CSSPropertyWebkitTransitionDelay:
3271 currValue = parseAnimationDelay();
3273 m_valueList->next();
3275 case CSSPropertyAnimationDirection:
3276 case CSSPropertyWebkitAnimationDirection:
3277 currValue = parseAnimationDirection();
3279 m_valueList->next();
3281 case CSSPropertyAnimationDuration:
3282 case CSSPropertyWebkitAnimationDuration:
3283 case CSSPropertyTransitionDuration:
3284 case CSSPropertyWebkitTransitionDuration:
3285 currValue = parseAnimationDuration();
3287 m_valueList->next();
3289 case CSSPropertyAnimationFillMode:
3290 case CSSPropertyWebkitAnimationFillMode:
3291 currValue = parseAnimationFillMode();
3293 m_valueList->next();
3295 case CSSPropertyAnimationIterationCount:
3296 case CSSPropertyWebkitAnimationIterationCount:
3297 currValue = parseAnimationIterationCount();
3299 m_valueList->next();
3301 case CSSPropertyAnimationName:
3302 case CSSPropertyWebkitAnimationName:
3303 currValue = parseAnimationName();
3305 m_valueList->next();
3307 case CSSPropertyAnimationPlayState:
3308 case CSSPropertyWebkitAnimationPlayState:
3309 currValue = parseAnimationPlayState();
3311 m_valueList->next();
3313 case CSSPropertyTransitionProperty:
3314 case CSSPropertyWebkitTransitionProperty:
3315 currValue = parseAnimationProperty(context);
3316 if (value && !context.animationPropertyKeywordAllowed())
3319 m_valueList->next();
3321 case CSSPropertyAnimationTimingFunction:
3322 case CSSPropertyWebkitAnimationTimingFunction:
3323 case CSSPropertyTransitionTimingFunction:
3324 case CSSPropertyWebkitTransitionTimingFunction:
3325 currValue = parseAnimationTimingFunction();
3327 m_valueList->next();
3330 ASSERT_NOT_REACHED();
3337 if (value && !values) {
3338 values = CSSValueList::createCommaSeparated();
3339 values->append(value.release());
3343 values->append(currValue.release());
3345 value = currValue.release();
3350 // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
3356 if (values && values->length()) {
3357 result = values.release();
3361 result = value.release();
3367 // The function parses [ <integer> || <string> ] in <grid-line> (which can be stand alone or with 'span').
3368 bool CSSPropertyParser::parseIntegerOrStringFromGridPosition(RefPtrWillBeRawPtr<CSSPrimitiveValue>& numericValue, RefPtrWillBeRawPtr<CSSPrimitiveValue>& gridLineName)
3370 CSSParserValue* value = m_valueList->current();
3371 if (validUnit(value, FInteger) && value->fValue) {
3372 numericValue = createPrimitiveNumericValue(value);
3373 value = m_valueList->next();
3374 if (value && value->unit == CSSPrimitiveValue::CSS_STRING) {
3375 gridLineName = createPrimitiveStringValue(m_valueList->current());
3376 m_valueList->next();
3381 if (value->unit == CSSPrimitiveValue::CSS_STRING) {
3382 gridLineName = createPrimitiveStringValue(m_valueList->current());
3383 value = m_valueList->next();
3384 if (value && validUnit(value, FInteger) && value->fValue) {
3385 numericValue = createPrimitiveNumericValue(value);
3386 m_valueList->next();
3394 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridPosition()
3396 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3398 CSSParserValue* value = m_valueList->current();
3399 if (value->id == CSSValueAuto) {
3400 m_valueList->next();
3401 return cssValuePool().createIdentifierValue(CSSValueAuto);
3404 if (value->id != CSSValueSpan && value->unit == CSSPrimitiveValue::CSS_IDENT) {
3405 m_valueList->next();
3406 return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
3409 RefPtrWillBeRawPtr<CSSPrimitiveValue> numericValue = nullptr;
3410 RefPtrWillBeRawPtr<CSSPrimitiveValue> gridLineName = nullptr;
3411 bool hasSeenSpanKeyword = false;
3413 if (parseIntegerOrStringFromGridPosition(numericValue, gridLineName)) {
3414 value = m_valueList->current();
3415 if (value && value->id == CSSValueSpan) {
3416 hasSeenSpanKeyword = true;
3417 m_valueList->next();
3419 } else if (value->id == CSSValueSpan) {
3420 hasSeenSpanKeyword = true;
3421 if (m_valueList->next())
3422 parseIntegerOrStringFromGridPosition(numericValue, gridLineName);
3425 // Check that we have consumed all the value list. For shorthands, the parser will pass
3426 // the whole value list (including the opposite position).
3427 if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current()))
3430 // If we didn't parse anything, this is not a valid grid position.
3431 if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
3434 // Negative numbers are not allowed for span (but are for <integer>).
3435 if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
3438 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
3439 if (hasSeenSpanKeyword)
3440 values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
3442 values->append(numericValue.release());
3444 values->append(gridLineName.release());
3445 ASSERT(values->length());
3446 return values.release();
3449 static PassRefPtrWillBeRawPtr<CSSValue> gridMissingGridPositionValue(CSSValue* value)
3451 if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isString())
3454 return cssValuePool().createIdentifierValue(CSSValueAuto);
3457 bool CSSPropertyParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
3459 ShorthandScope scope(this, shorthandId);
3460 const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
3461 ASSERT(shorthand.length() == 2);
3463 RefPtrWillBeRawPtr<CSSValue> startValue = parseGridPosition();
3467 RefPtrWillBeRawPtr<CSSValue> endValue = nullptr;
3468 if (m_valueList->current()) {
3469 if (!isForwardSlashOperator(m_valueList->current()))
3472 if (!m_valueList->next())
3475 endValue = parseGridPosition();
3476 if (!endValue || m_valueList->current())
3479 endValue = gridMissingGridPositionValue(startValue.get());
3482 addProperty(shorthand.properties()[0], startValue, important);
3483 addProperty(shorthand.properties()[1], endValue, important);
3487 bool CSSPropertyParser::parseGridTemplateRowsAndAreas(PassRefPtrWillBeRawPtr<CSSValue> templateColumns, bool important)
3489 NamedGridAreaMap gridAreaMap;
3490 size_t rowCount = 0;
3491 size_t columnCount = 0;
3492 bool trailingIdentWasAdded = false;
3493 RefPtrWillBeRawPtr<CSSValueList> templateRows = CSSValueList::createSpaceSeparated();
3495 // At least template-areas strings must be defined.
3496 if (!m_valueList->current())
3499 while (m_valueList->current()) {
3500 // Handle leading <custom-ident>*.
3501 if (m_valueList->current()->unit == CSSParserValue::ValueList) {
3502 if (trailingIdentWasAdded) {
3503 // A row's trailing ident must be concatenated with the next row's leading one.
3504 parseGridLineNames(*m_valueList, *templateRows, static_cast<CSSGridLineNamesValue*>(templateRows->item(templateRows->length() - 1)));
3506 parseGridLineNames(*m_valueList, *templateRows);
3510 // Handle a template-area's row.
3511 if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
3515 // Handle template-rows's track-size.
3516 if (m_valueList->current() && m_valueList->current()->unit != CSSParserValue::ValueList && m_valueList->current()->unit != CSSPrimitiveValue::CSS_STRING) {
3517 RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
3520 templateRows->append(value);
3522 templateRows->append(cssValuePool().createIdentifierValue(CSSValueAuto));
3525 // This will handle the trailing/leading <custom-ident>* in the grammar.
3526 trailingIdentWasAdded = false;
3527 if (m_valueList->current() && m_valueList->current()->unit == CSSParserValue::ValueList) {
3528 parseGridLineNames(*m_valueList, *templateRows);
3529 trailingIdentWasAdded = true;
3533 // [<track-list> /]?
3534 if (templateColumns)
3535 addProperty(CSSPropertyGridTemplateColumns, templateColumns, important);
3537 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createIdentifierValue(CSSValueNone), important);
3539 // [<line-names>? <string> [<track-size> <line-names>]? ]+
3540 RefPtrWillBeRawPtr<CSSValue> templateAreas = CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
3541 addProperty(CSSPropertyGridTemplateAreas, templateAreas.release(), important);
3542 addProperty(CSSPropertyGridTemplateRows, templateRows.release(), important);
3549 bool CSSPropertyParser::parseGridTemplateShorthand(bool important)
3551 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3553 ShorthandScope scope(this, CSSPropertyGridTemplate);
3554 ASSERT(gridTemplateShorthand().length() == 3);
3556 // At least "none" must be defined.
3557 if (!m_valueList->current())
3560 bool firstValueIsNone = m_valueList->current()->id == CSSValueNone;
3563 if (firstValueIsNone && !m_valueList->next()) {
3564 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createIdentifierValue(CSSValueNone), important);
3565 addProperty(CSSPropertyGridTemplateRows, cssValuePool().createIdentifierValue(CSSValueNone), important);
3566 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifierValue(CSSValueNone), important);
3571 RefPtrWillBeRawPtr<CSSValue> columnsValue = nullptr;
3572 if (firstValueIsNone) {
3573 columnsValue = cssValuePool().createIdentifierValue(CSSValueNone);
3575 columnsValue = parseGridTrackList(important);
3578 // 2- <grid-template-columns> / <grid-template-columns> syntax.
3580 if (!(m_valueList->current() && isForwardSlashOperator(m_valueList->current()) && m_valueList->next()))
3582 index = m_valueList->currentIndex();
3583 if (RefPtrWillBeRawPtr<CSSValue> rowsValue = parseGridTrackList(important)) {
3584 if (m_valueList->current())
3586 addProperty(CSSPropertyGridTemplateColumns, columnsValue, important);
3587 addProperty(CSSPropertyGridTemplateRows, rowsValue, important);
3588 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifierValue(CSSValueNone), important);
3594 // 3- [<track-list> /]? [<line-names>? <string> [<track-size> <line-names>]? ]+ syntax.
3595 // The template-columns <track-list> can't be 'none'.
3596 if (firstValueIsNone)
3598 // It requires to rewind parsing due to previous syntax failures.
3599 m_valueList->setCurrentIndex(index);
3600 return parseGridTemplateRowsAndAreas(columnsValue, important);
3603 bool CSSPropertyParser::parseGridShorthand(bool important)
3605 ShorthandScope scope(this, CSSPropertyGrid);
3606 ASSERT(shorthandForProperty(CSSPropertyGrid).length() == 4);
3608 // 1- <grid-template>
3609 if (parseGridTemplateShorthand(important)) {
3610 // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
3611 // The sub-properties not specified are set to their initial value, as normal for shorthands.
3612 addProperty(CSSPropertyGridAutoFlow, cssValuePool().createImplicitInitialValue(), important);
3613 addProperty(CSSPropertyGridAutoColumns, cssValuePool().createImplicitInitialValue(), important);
3614 addProperty(CSSPropertyGridAutoRows, cssValuePool().createImplicitInitialValue(), important);
3618 // Need to rewind parsing to explore the alternative syntax of this shorthand.
3619 m_valueList->setCurrentIndex(0);
3621 // 2- <grid-auto-flow> [ <grid-auto-columns> [ / <grid-auto-rows> ]? ]
3622 CSSValueID id = m_valueList->current()->id;
3623 if (id != CSSValueRow && id != CSSValueColumn && id != CSSValueNone)
3626 RefPtrWillBeRawPtr<CSSValue> autoFlowValue = cssValuePool().createIdentifierValue(id);
3627 RefPtrWillBeRawPtr<CSSValue> autoColumnsValue = nullptr;
3628 RefPtrWillBeRawPtr<CSSValue> autoRowsValue = nullptr;
3630 if (m_valueList->next()) {
3631 autoColumnsValue = parseGridTrackSize(*m_valueList);
3632 if (!autoColumnsValue)
3634 if (m_valueList->current()) {
3635 if (!isForwardSlashOperator(m_valueList->current()) || !m_valueList->next())
3637 autoRowsValue = parseGridTrackSize(*m_valueList);
3641 if (m_valueList->current())
3644 // Other omitted values are set to their initial values.
3645 autoColumnsValue = cssValuePool().createImplicitInitialValue();
3646 autoRowsValue = cssValuePool().createImplicitInitialValue();
3649 // if <grid-auto-rows> value is omitted, it is set to the value specified for grid-auto-columns.
3651 autoRowsValue = autoColumnsValue;
3653 addProperty(CSSPropertyGridAutoFlow, autoFlowValue, important);
3654 addProperty(CSSPropertyGridAutoColumns, autoColumnsValue, important);
3655 addProperty(CSSPropertyGridAutoRows, autoRowsValue, important);
3657 // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
3658 // The sub-properties not specified are set to their initial value, as normal for shorthands.
3659 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createImplicitInitialValue(), important);
3660 addProperty(CSSPropertyGridTemplateRows, cssValuePool().createImplicitInitialValue(), important);
3661 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createImplicitInitialValue(), important);
3666 bool CSSPropertyParser::parseGridAreaShorthand(bool important)
3668 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3670 ShorthandScope scope(this, CSSPropertyGridArea);
3671 const StylePropertyShorthand& shorthand = gridAreaShorthand();
3672 ASSERT_UNUSED(shorthand, shorthand.length() == 4);
3674 RefPtrWillBeRawPtr<CSSValue> rowStartValue = parseGridPosition();
3678 RefPtrWillBeRawPtr<CSSValue> columnStartValue = nullptr;
3679 if (!parseSingleGridAreaLonghand(columnStartValue))
3682 RefPtrWillBeRawPtr<CSSValue> rowEndValue = nullptr;
3683 if (!parseSingleGridAreaLonghand(rowEndValue))
3686 RefPtrWillBeRawPtr<CSSValue> columnEndValue = nullptr;
3687 if (!parseSingleGridAreaLonghand(columnEndValue))
3690 if (!columnStartValue)
3691 columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
3694 rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
3696 if (!columnEndValue)
3697 columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
3699 addProperty(CSSPropertyGridRowStart, rowStartValue, important);
3700 addProperty(CSSPropertyGridColumnStart, columnStartValue, important);
3701 addProperty(CSSPropertyGridRowEnd, rowEndValue, important);
3702 addProperty(CSSPropertyGridColumnEnd, columnEndValue, important);
3706 bool CSSPropertyParser::parseSingleGridAreaLonghand(RefPtrWillBeRawPtr<CSSValue>& property)
3708 if (!m_valueList->current())
3711 if (!isForwardSlashOperator(m_valueList->current()))
3714 if (!m_valueList->next())
3717 property = parseGridPosition();
3721 void CSSPropertyParser::parseGridLineNames(CSSParserValueList& inputList, CSSValueList& valueList, CSSGridLineNamesValue* previousNamedAreaTrailingLineNames)
3723 ASSERT(inputList.current() && inputList.current()->unit == CSSParserValue::ValueList);
3725 CSSParserValueList* identList = inputList.current()->valueList;
3726 if (!identList->size()) {
3731 // Need to ensure the identList is at the heading index, since the parserList might have been rewound.
3732 identList->setCurrentIndex(0);
3734 RefPtrWillBeRawPtr<CSSGridLineNamesValue> lineNames = previousNamedAreaTrailingLineNames;
3736 lineNames = CSSGridLineNamesValue::create();
3737 while (CSSParserValue* identValue = identList->current()) {
3738 ASSERT(identValue->unit == CSSPrimitiveValue::CSS_IDENT);
3739 RefPtrWillBeRawPtr<CSSPrimitiveValue> lineName = createPrimitiveStringValue(identValue);
3740 lineNames->append(lineName.release());
3743 if (!previousNamedAreaTrailingLineNames)
3744 valueList.append(lineNames.release());
3749 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackList(bool important)
3751 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3753 CSSParserValue* value = m_valueList->current();
3754 if (value->id == CSSValueNone) {
3755 m_valueList->next();
3756 return cssValuePool().createIdentifierValue(CSSValueNone);
3759 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
3760 // Handle leading <ident>*.
3761 value = m_valueList->current();
3762 if (value && value->unit == CSSParserValue::ValueList)
3763 parseGridLineNames(*m_valueList, *values);
3765 bool seenTrackSizeOrRepeatFunction = false;
3766 while (CSSParserValue* currentValue = m_valueList->current()) {
3767 if (isForwardSlashOperator(currentValue))
3769 if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "repeat(")) {
3770 if (!parseGridTrackRepeatFunction(*values))
3772 seenTrackSizeOrRepeatFunction = true;
3774 RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
3777 values->append(value);
3778 seenTrackSizeOrRepeatFunction = true;
3780 // This will handle the trailing <ident>* in the grammar.
3781 value = m_valueList->current();
3782 if (value && value->unit == CSSParserValue::ValueList)
3783 parseGridLineNames(*m_valueList, *values);
3786 // We should have found a <track-size> or else it is not a valid <track-list>
3787 if (!seenTrackSizeOrRepeatFunction)
3793 bool CSSPropertyParser::parseGridTrackRepeatFunction(CSSValueList& list)
3795 CSSParserValueList* arguments = m_valueList->current()->function->args.get();
3796 if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1)))
3799 ASSERT_WITH_SECURITY_IMPLICATION(arguments->valueAt(0)->fValue > 0);
3800 size_t repetitions = arguments->valueAt(0)->fValue;
3801 // Clamp repetitions at minRepetitions.
3802 // http://www.w3.org/TR/css-grid-1/#repeat-notation
3803 if (repetitions > minRepetitions)
3804 repetitions = minRepetitions;
3805 RefPtrWillBeRawPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
3806 arguments->next(); // Skip the repetition count.
3807 arguments->next(); // Skip the comma.
3809 // Handle leading <ident>*.
3810 CSSParserValue* currentValue = arguments->current();
3811 if (currentValue && currentValue->unit == CSSParserValue::ValueList)
3812 parseGridLineNames(*arguments, *repeatedValues);
3814 while (arguments->current()) {
3815 RefPtrWillBeRawPtr<CSSValue> trackSize = parseGridTrackSize(*arguments);
3819 repeatedValues->append(trackSize);
3821 // This takes care of any trailing <ident>* in the grammar.
3822 currentValue = arguments->current();
3823 if (currentValue && currentValue->unit == CSSParserValue::ValueList)
3824 parseGridLineNames(*arguments, *repeatedValues);
3827 for (size_t i = 0; i < repetitions; ++i) {
3828 for (size_t j = 0; j < repeatedValues->length(); ++j)
3829 list.append(repeatedValues->itemWithoutBoundsCheck(j));
3832 // parseGridTrackSize iterated over the repeat arguments, move to the next value.
3833 m_valueList->next();
3838 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackSize(CSSParserValueList& inputList)
3840 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3842 CSSParserValue* currentValue = inputList.current();
3845 if (currentValue->id == CSSValueAuto)
3846 return cssValuePool().createIdentifierValue(CSSValueAuto);
3848 if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax(")) {
3849 // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
3850 CSSParserValueList* arguments = currentValue->function->args.get();
3851 if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
3854 RefPtrWillBeRawPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0));
3855 if (!minTrackBreadth)
3858 RefPtrWillBeRawPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2));
3859 if (!maxTrackBreadth)
3862 RefPtrWillBeRawPtr<CSSValueList> parsedArguments = CSSValueList::createCommaSeparated();
3863 parsedArguments->append(minTrackBreadth);
3864 parsedArguments->append(maxTrackBreadth);
3865 return CSSFunctionValue::create("minmax(", parsedArguments);
3868 return parseGridBreadth(currentValue);
3871 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseGridBreadth(CSSParserValue* currentValue)
3873 if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMaxContent)
3874 return cssValuePool().createIdentifierValue(currentValue->id);
3876 if (currentValue->unit == CSSPrimitiveValue::CSS_FR) {
3877 double flexValue = currentValue->fValue;
3879 // Fractional unit is a non-negative dimension.
3883 return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR);
3886 if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
3889 return createPrimitiveNumericValue(currentValue);
3892 bool CSSPropertyParser::parseGridTemplateAreasRow(NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount)
3894 CSSParserValue* currentValue = m_valueList->current();
3895 if (!currentValue || currentValue->unit != CSSPrimitiveValue::CSS_STRING)
3898 String gridRowNames = currentValue->string;
3899 if (!gridRowNames.length())
3902 Vector<String> columnNames;
3903 gridRowNames.split(' ', columnNames);
3906 columnCount = columnNames.size();
3907 ASSERT(columnCount);
3908 } else if (columnCount != columnNames.size()) {
3909 // The declaration is invalid is all the rows don't have the number of columns.
3913 for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
3914 const String& gridAreaName = columnNames[currentCol];
3916 // Unamed areas are always valid (we consider them to be 1x1).
3917 if (gridAreaName == ".")
3920 // We handle several grid areas with the same name at once to simplify the validation code.
3921 size_t lookAheadCol;
3922 for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++lookAheadCol) {
3923 if (columnNames[lookAheadCol + 1] != gridAreaName)
3927 NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
3928 if (gridAreaIt == gridAreaMap.end()) {
3929 gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowCount), GridSpan(currentCol, lookAheadCol)));
3931 GridCoordinate& gridCoordinate = gridAreaIt->value;
3933 // The following checks test that the grid area is a single filled-in rectangle.
3934 // 1. The new row is adjacent to the previously parsed row.
3935 if (rowCount != gridCoordinate.rows.resolvedFinalPosition.next().toInt())
3938 // 2. The new area starts at the same position as the previously parsed area.
3939 if (currentCol != gridCoordinate.columns.resolvedInitialPosition.toInt())
3942 // 3. The new area ends at the same position as the previously parsed area.
3943 if (lookAheadCol != gridCoordinate.columns.resolvedFinalPosition.toInt())
3946 ++gridCoordinate.rows.resolvedFinalPosition;
3948 currentCol = lookAheadCol;
3951 m_valueList->next();
3955 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTemplateAreas()
3957 NamedGridAreaMap gridAreaMap;
3958 size_t rowCount = 0;
3959 size_t columnCount = 0;
3961 while (m_valueList->current()) {
3962 if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
3967 if (!rowCount || !columnCount)
3970 return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
3973 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseCounterContent(CSSParserValueList* args, bool counters)
3975 unsigned numArgs = args->size();
3976 if (counters && numArgs != 3 && numArgs != 5)
3978 if (!counters && numArgs != 1 && numArgs != 3)
3981 CSSParserValue* i = args->current();
3982 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
3984 RefPtrWillBeRawPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i);
3986 RefPtrWillBeRawPtr<CSSPrimitiveValue> separator = nullptr;
3988 separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING);
3991 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
3995 if (i->unit != CSSPrimitiveValue::CSS_STRING)
3998 separator = createPrimitiveStringValue(i);
4001 RefPtrWillBeRawPtr<CSSPrimitiveValue> listStyle = nullptr;
4003 if (!i) // Make the list style default decimal
4004 listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
4006 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
4010 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
4013 CSSValueID listStyleID = CSSValueInvalid;
4014 if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha))
4015 listStyleID = i->id;
4019 listStyle = cssValuePool().createIdentifierValue(listStyleID);
4022 return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
4025 bool CSSPropertyParser::parseClipShape(CSSPropertyID propId, bool important)
4027 CSSParserValue* value = m_valueList->current();
4028 CSSParserValueList* args = value->function->args.get();
4030 if (!equalIgnoringCase(value->function->name, "rect(") || !args)
4033 // rect(t, r, b, l) || rect(t r b l)
4034 if (args->size() != 4 && args->size() != 7)
4036 RefPtrWillBeRawPtr<Rect> rect = Rect::create();
4039 CSSParserValue* a = args->current();
4041 valid = a->id == CSSValueAuto || validUnit(a, FLength);
4044 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
4045 cssValuePool().createIdentifierValue(CSSValueAuto) :
4046 createPrimitiveNumericValue(a);
4048 rect->setTop(length);
4050 rect->setRight(length);
4052 rect->setBottom(length);
4054 rect->setLeft(length);
4056 if (a && args->size() == 7) {
4057 if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
4067 addProperty(propId, cssValuePool().createValue(rect.release()), important);
4068 m_valueList->next();
4074 static void completeBorderRadii(RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[4])
4080 radii[1] = radii[0];
4081 radii[2] = radii[0];
4083 radii[3] = radii[1];
4086 // FIXME: This should be refactored with CSSParser::parseBorderRadius.
4087 // CSSParser::parseBorderRadius contains support for some legacy radius construction.
4088 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseInsetRoundedCorners(PassRefPtrWillBeRawPtr<CSSBasicShapeInset> shape, CSSParserValueList* args)
4090 CSSParserValue* argument = args->next();
4095 Vector<CSSParserValue*> radiusArguments;
4097 radiusArguments.append(argument);
4098 argument = args->next();
4101 unsigned num = radiusArguments.size();
4102 if (!num || num > 9)
4105 // FIXME: Refactor completeBorderRadii and the array
4106 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
4108 // Zero initialize the array of raw pointers.
4109 memset(&radii, 0, sizeof(radii));
4112 unsigned indexAfterSlash = 0;
4113 for (unsigned i = 0; i < num; ++i) {
4114 CSSParserValue* value = radiusArguments.at(i);
4115 if (value->unit == CSSParserValue::Operator) {
4116 if (value->iValue != '/')
4119 if (!i || indexAfterSlash || i + 1 == num)
4122 indexAfterSlash = i + 1;
4123 completeBorderRadii(radii[0]);
4127 if (i - indexAfterSlash >= 4)
4130 if (!validUnit(value, FLength | FPercent | FNonNeg))
4133 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
4135 if (!indexAfterSlash)
4136 radii[0][i] = radius;
4138 radii[1][i - indexAfterSlash] = radius.release();
4141 if (!indexAfterSlash) {
4142 completeBorderRadii(radii[0]);
4143 for (unsigned i = 0; i < 4; ++i)
4144 radii[1][i] = radii[0][i];
4146 completeBorderRadii(radii[1]);
4148 shape->setTopLeftRadius(createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()));
4149 shape->setTopRightRadius(createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()));
4150 shape->setBottomRightRadius(createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()));
4151 shape->setBottomLeftRadius(createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()));
4156 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeInset(CSSParserValueList* args)
4160 RefPtrWillBeRawPtr<CSSBasicShapeInset> shape = CSSBasicShapeInset::create();
4162 CSSParserValue* argument = args->current();
4163 WillBeHeapVector<RefPtrWillBeMember<CSSPrimitiveValue> > widthArguments;
4164 bool hasRoundedInset = false;
4167 if (argument->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(argument->string, "round")) {
4168 hasRoundedInset = true;
4172 Units unitFlags = FLength | FPercent;
4173 if (!validUnit(argument, unitFlags) || widthArguments.size() > 4)
4176 widthArguments.append(createPrimitiveNumericValue(argument));
4177 argument = args->next();
4180 switch (widthArguments.size()) {
4182 shape->updateShapeSize1Value(widthArguments[0].get());
4186 shape->updateShapeSize2Values(widthArguments[0].get(), widthArguments[1].get());
4190 shape->updateShapeSize3Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get());
4194 shape->updateShapeSize4Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get(), widthArguments[3].get());
4201 if (hasRoundedInset)
4202 return parseInsetRoundedCorners(shape, args);
4206 static bool isItemPositionKeyword(CSSValueID id)
4208 return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
4209 || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
4210 || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight;
4213 bool CSSPropertyParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important)
4215 // auto | baseline | stretch | [<item-position> && <overflow-position>? ]
4216 // <item-position> = center | start | end | self-start | self-end | flex-start | flex-end | left | right;
4217 // <overflow-position> = true | safe
4219 CSSParserValue* value = m_valueList->current();
4221 if (value->id == CSSValueAuto || value->id == CSSValueBaseline || value->id == CSSValueStretch) {
4222 if (m_valueList->next())
4225 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
4229 RefPtrWillBeRawPtr<CSSPrimitiveValue> position = nullptr;
4230 RefPtrWillBeRawPtr<CSSPrimitiveValue> overflowAlignmentKeyword = nullptr;
4231 if (isItemPositionKeyword(value->id)) {
4232 position = cssValuePool().createIdentifierValue(value->id);
4233 value = m_valueList->next();
4235 if (value->id == CSSValueTrue || value->id == CSSValueSafe)
4236 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
4240 } else if (value->id == CSSValueTrue || value->id == CSSValueSafe) {
4241 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
4242 value = m_valueList->next();
4244 if (isItemPositionKeyword(value->id))
4245 position = cssValuePool().createIdentifierValue(value->id);
4253 if (m_valueList->next())
4257 if (overflowAlignmentKeyword)
4258 addProperty(propId, createPrimitiveValuePair(position, overflowAlignmentKeyword), important);
4260 addProperty(propId, position.release(), important);
4265 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseShapeRadius(CSSParserValue* value)
4267 if (value->id == CSSValueClosestSide || value->id == CSSValueFarthestSide)
4268 return cssValuePool().createIdentifierValue(value->id);
4270 if (!validUnit(value, FLength | FPercent | FNonNeg))
4273 return createPrimitiveNumericValue(value);
4276 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeCircle(CSSParserValueList* args)
4281 // circle(radius at <position>)
4282 // circle(at <position>)
4283 // where position defines centerX and centerY using a CSS <position> data type.
4284 RefPtrWillBeRawPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
4286 for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
4287 // The call to parseFillPosition below should consume all of the
4288 // arguments except the first two. Thus, and index greater than one
4289 // indicates an invalid production.
4290 if (args->currentIndex() > 1)
4293 if (!args->currentIndex() && argument->id != CSSValueAt) {
4294 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
4295 shape->setRadius(radius);
4302 if (argument->id == CSSValueAt && args->next()) {
4303 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
4304 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
4305 parseFillPosition(args, centerX, centerY);
4306 if (centerX && centerY && !args->current()) {
4307 ASSERT(centerX->isPrimitiveValue());
4308 ASSERT(centerY->isPrimitiveValue());
4309 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
4310 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
4322 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeEllipse(CSSParserValueList* args)
4327 // ellipse(radiusX at <position>)
4328 // ellipse(radiusX radiusY)
4329 // ellipse(radiusX radiusY at <position>)
4330 // ellipse(at <position>)
4331 // where position defines centerX and centerY using a CSS <position> data type.
4332 RefPtrWillBeRawPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
4334 for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
4335 // The call to parseFillPosition below should consume all of the
4336 // arguments except the first three. Thus, an index greater than two
4337 // indicates an invalid production.
4338 if (args->currentIndex() > 2)
4341 if (args->currentIndex() < 2 && argument->id != CSSValueAt) {
4342 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
4343 if (!shape->radiusX())
4344 shape->setRadiusX(radius);
4346 shape->setRadiusY(radius);
4353 if (argument->id != CSSValueAt || !args->next()) // expecting ellipse(.. at <position>)
4355 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
4356 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
4357 parseFillPosition(args, centerX, centerY);
4358 if (!centerX || !centerY || args->current())
4361 ASSERT(centerX->isPrimitiveValue());
4362 ASSERT(centerY->isPrimitiveValue());
4363 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
4364 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
4370 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapePolygon(CSSParserValueList* args)
4374 unsigned size = args->size();
4378 RefPtrWillBeRawPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
4380 CSSParserValue* argument = args->current();
4381 if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
4382 shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
4384 if (!isComma(args->next()))
4387 argument = args->next();
4391 // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one
4392 if (!size || (size % 3) - 2)
4395 CSSParserValue* argumentX = argument;
4398 if (!validUnit(argumentX, FLength | FPercent))
4400 RefPtrWillBeRawPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX);
4402 CSSParserValue* argumentY = args->next();
4403 if (!argumentY || !validUnit(argumentY, FLength | FPercent))
4406 RefPtrWillBeRawPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY);
4408 shape->appendPoint(xLength.release(), yLength.release());
4410 CSSParserValue* commaOrNull = args->next();
4413 else if (!isComma(commaOrNull))
4416 argumentX = args->next();
4422 static bool isBoxValue(CSSValueID valueId)
4425 case CSSValueContentBox:
4426 case CSSValuePaddingBox:
4427 case CSSValueBorderBox:
4428 case CSSValueMarginBox:
4437 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseShapeProperty(CSSPropertyID propId)
4439 if (!RuntimeEnabledFeatures::cssShapesEnabled())
4442 CSSParserValue* value = m_valueList->current();
4443 CSSValueID valueId = value->id;
4445 if (valueId == CSSValueNone) {
4446 RefPtrWillBeRawPtr<CSSPrimitiveValue> keywordValue = parseValidPrimitive(valueId, value);
4447 m_valueList->next();
4448 return keywordValue.release();
4451 RefPtrWillBeRawPtr<CSSValue> imageValue = nullptr;
4452 if (valueId != CSSValueNone && parseFillImage(m_valueList.get(), imageValue)) {
4453 m_valueList->next();
4454 return imageValue.release();
4457 return parseBasicShapeAndOrBox();
4460 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBasicShapeAndOrBox()
4462 CSSParserValue* value = m_valueList->current();
4464 bool shapeFound = false;
4465 bool boxFound = false;
4468 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
4469 for (unsigned i = 0; i < 2; ++i) {
4472 valueId = value->id;
4473 if (value->unit == CSSParserValue::Function && !shapeFound) {
4474 // parseBasicShape already asks for the next value list item.
4475 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = parseBasicShape();
4478 list->append(shapeValue.release());
4480 } else if (isBoxValue(valueId) && !boxFound) {
4481 list->append(parseValidPrimitive(valueId, value));
4483 m_valueList->next();
4488 value = m_valueList->current();
4491 if (m_valueList->current())
4493 return list.release();
4496 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseBasicShape()
4498 CSSParserValue* value = m_valueList->current();
4499 ASSERT(value->unit == CSSParserValue::Function);
4500 CSSParserValueList* args = value->function->args.get();
4505 RefPtrWillBeRawPtr<CSSBasicShape> shape = nullptr;
4506 if (equalIgnoringCase(value->function->name, "circle("))
4507 shape = parseBasicShapeCircle(args);
4508 else if (equalIgnoringCase(value->function->name, "ellipse("))
4509 shape = parseBasicShapeEllipse(args);
4510 else if (equalIgnoringCase(value->function->name, "polygon("))
4511 shape = parseBasicShapePolygon(args);
4512 else if (equalIgnoringCase(value->function->name, "inset("))
4513 shape = parseBasicShapeInset(args);
4518 m_valueList->next();
4520 return cssValuePool().createValue(shape.release());
4523 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
4524 bool CSSPropertyParser::parseFont(bool important)
4526 // Let's check if there is an inherit or initial somewhere in the shorthand.
4527 for (unsigned i = 0; i < m_valueList->size(); ++i) {
4528 if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial)
4532 ShorthandScope scope(this, CSSPropertyFont);
4533 // Optional font-style, font-variant and font-weight.
4534 bool fontStyleParsed = false;
4535 bool fontVariantParsed = false;
4536 bool fontWeightParsed = false;
4537 CSSParserValue* value;
4538 while ((value = m_valueList->current())) {
4539 if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
4540 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
4541 fontStyleParsed = true;
4542 } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
4543 // Font variant in the shorthand is particular, it only accepts normal or small-caps.
4544 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important);
4545 fontVariantParsed = true;
4546 } else if (!fontWeightParsed && parseFontWeight(important))
4547 fontWeightParsed = true;
4550 m_valueList->next();
4556 if (!fontStyleParsed)
4557 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4558 if (!fontVariantParsed)
4559 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4560 if (!fontWeightParsed)
4561 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4563 // Now a font size _must_ come.
4564 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
4565 if (!parseFontSize(important))
4568 value = m_valueList->current();
4572 if (isForwardSlashOperator(value)) {
4573 // The line-height property.
4574 value = m_valueList->next();
4577 if (!parseLineHeight(important))
4580 addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4582 // Font family must come now.
4583 RefPtrWillBeRawPtr<CSSValue> parsedFamilyValue = parseFontFamily();
4584 if (!parsedFamilyValue)
4587 addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
4589 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
4590 // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
4591 // but we don't seem to support them at the moment. They should also be added here once implemented.
4592 if (m_valueList->current())
4598 class FontFamilyValueBuilder {
4599 DISALLOW_ALLOCATION();
4601 FontFamilyValueBuilder(CSSValueList* list)
4606 void add(const CSSParserString& string)
4608 if (!m_builder.isEmpty())
4609 m_builder.append(' ');
4611 if (string.is8Bit()) {
4612 m_builder.append(string.characters8(), string.length());
4616 m_builder.append(string.characters16(), string.length());
4621 if (m_builder.isEmpty())
4623 m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString()));
4628 StringBuilder m_builder;
4629 CSSValueList* m_list;
4632 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFontFamily()
4634 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
4635 CSSParserValue* value = m_valueList->current();
4637 FontFamilyValueBuilder familyBuilder(list.get());
4638 bool inFamily = false;
4641 CSSParserValue* nextValue = m_valueList->next();
4642 bool nextValBreaksFont = !nextValue ||
4643 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
4644 bool nextValIsFontName = nextValue &&
4645 ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
4646 (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
4648 bool valueIsKeyword = value->id == CSSValueInitial || value->id == CSSValueInherit || value->id == CSSValueDefault;
4649 if (valueIsKeyword && !inFamily) {
4650 if (nextValBreaksFont)
4651 value = m_valueList->next();
4652 else if (nextValIsFontName)
4657 if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
4659 familyBuilder.add(value->string);
4660 else if (nextValBreaksFont || !nextValIsFontName)
4661 list->append(cssValuePool().createIdentifierValue(value->id));
4663 familyBuilder.commit();
4664 familyBuilder.add(value->string);
4667 } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
4668 // Strings never share in a family name.
4670 familyBuilder.commit();
4671 list->append(cssValuePool().createFontFamilyValue(value->string));
4672 } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
4674 familyBuilder.add(value->string);
4675 else if (nextValBreaksFont || !nextValIsFontName)
4676 list->append(cssValuePool().createFontFamilyValue(value->string));
4678 familyBuilder.commit();
4679 familyBuilder.add(value->string);
4689 if (nextValBreaksFont) {
4690 value = m_valueList->next();
4691 familyBuilder.commit();
4694 else if (nextValIsFontName)
4699 familyBuilder.commit();
4701 if (!list->length())
4703 return list.release();
4706 bool CSSPropertyParser::parseLineHeight(bool important)
4708 CSSParserValue* value = m_valueList->current();
4709 CSSValueID id = value->id;
4710 bool validPrimitive = false;
4711 // normal | <number> | <length> | <percentage> | inherit
4712 if (id == CSSValueNormal)
4713 validPrimitive = true;
4715 validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
4716 if (validPrimitive && (!m_valueList->next() || inShorthand()))
4717 addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important);
4718 return validPrimitive;
4721 bool CSSPropertyParser::parseFontSize(bool important)
4723 CSSParserValue* value = m_valueList->current();
4724 CSSValueID id = value->id;
4725 bool validPrimitive = false;
4726 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
4727 if (id >= CSSValueXxSmall && id <= CSSValueLarger)
4728 validPrimitive = true;
4730 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
4731 if (validPrimitive && (!m_valueList->next() || inShorthand()))
4732 addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important);
4733 return validPrimitive;
4736 bool CSSPropertyParser::parseFontVariant(bool important)
4738 RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
4739 if (m_valueList->size() > 1)
4740 values = CSSValueList::createCommaSeparated();
4741 CSSParserValue* val;
4742 bool expectComma = false;
4743 while ((val = m_valueList->current())) {
4744 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue = nullptr;
4747 if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
4748 parsedValue = cssValuePool().createIdentifierValue(val->id);
4749 else if (val->id == CSSValueAll && !values) {
4750 // 'all' is only allowed in @font-face and with no other values. Make a value list to
4751 // indicate that we are in the @font-face case.
4752 values = CSSValueList::createCommaSeparated();
4753 parsedValue = cssValuePool().createIdentifierValue(val->id);
4755 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
4756 expectComma = false;
4757 m_valueList->next();
4764 m_valueList->next();
4767 values->append(parsedValue.release());
4769 addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
4774 if (values && values->length()) {
4775 m_hasFontFaceOnlyValues = true;
4776 addProperty(CSSPropertyFontVariant, values.release(), important);
4783 bool CSSPropertyParser::parseFontWeight(bool important)
4785 CSSParserValue* value = m_valueList->current();
4786 if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
4787 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important);
4790 if (validUnit(value, FInteger | FNonNeg, HTMLQuirksMode)) {
4791 int weight = static_cast<int>(value->fValue);
4792 if (!(weight % 100) && weight >= 100 && weight <= 900) {
4793 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1)), important);
4800 bool CSSPropertyParser::parseFontFaceSrcURI(CSSValueList* valueList)
4802 RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string)));
4803 uriValue->setReferrer(m_context.baseURL().strippedForUseAsReferrer());
4805 CSSParserValue* value = m_valueList->next();
4807 valueList->append(uriValue.release());
4810 if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
4811 m_valueList->next();
4812 valueList->append(uriValue.release());
4816 if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format("))
4819 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
4820 // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
4821 CSSParserValueList* args = value->function->args.get();
4822 if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
4824 uriValue->setFormat(args->current()->string);
4825 valueList->append(uriValue.release());
4826 value = m_valueList->next();
4827 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
4828 m_valueList->next();
4832 bool CSSPropertyParser::parseFontFaceSrcLocal(CSSValueList* valueList)
4834 CSSParserValueList* args = m_valueList->current()->function->args.get();
4835 if (!args || !args->size())
4838 if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING)
4839 valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string));
4840 else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
4841 StringBuilder builder;
4842 for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) {
4843 if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
4845 if (!builder.isEmpty())
4846 builder.append(' ');
4847 builder.append(localValue->string);
4849 valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
4853 if (CSSParserValue* value = m_valueList->next()) {
4854 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
4855 m_valueList->next();
4860 bool CSSPropertyParser::parseFontFaceSrc()
4862 RefPtrWillBeRawPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
4864 while (CSSParserValue* value = m_valueList->current()) {
4865 if (value->unit == CSSPrimitiveValue::CSS_URI) {
4866 if (!parseFontFaceSrcURI(values.get()))
4868 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) {
4869 if (!parseFontFaceSrcLocal(values.get()))
4874 if (!values->length())
4877 addProperty(CSSPropertySrc, values.release(), m_important);
4878 m_valueList->next();
4882 bool CSSPropertyParser::parseFontFaceUnicodeRange()
4884 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
4885 bool failed = false;
4886 bool operatorExpected = false;
4887 for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
4888 if (operatorExpected) {
4889 if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
4894 if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
4899 String rangeString = m_valueList->current()->string;
4902 unsigned length = rangeString.length();
4910 while (i < length) {
4911 UChar c = rangeString[i];
4912 if (c == '-' || c == '?')
4915 if (c >= '0' && c <= '9')
4917 else if (c >= 'A' && c <= 'F')
4918 from += 10 + c - 'A';
4919 else if (c >= 'a' && c <= 'f')
4920 from += 10 + c - 'a';
4932 else if (rangeString[i] == '?') {
4934 while (i < length && rangeString[i] == '?') {
4941 to = from + span - 1;
4943 if (length < i + 2) {
4948 while (i < length) {
4949 UChar c = rangeString[i];
4951 if (c >= '0' && c <= '9')
4953 else if (c >= 'A' && c <= 'F')
4955 else if (c >= 'a' && c <= 'f')
4967 values->append(CSSUnicodeRangeValue::create(from, to));
4969 if (failed || !values->length())
4971 addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
4975 // Returns the number of characters which form a valid double
4976 // and are terminated by the given terminator character
4977 template <typename CharacterType>
4978 static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
4980 int length = end - string;
4984 bool decimalMarkSeen = false;
4985 int processedLength = 0;
4987 for (int i = 0; i < length; ++i) {
4988 if (string[i] == terminator) {
4989 processedLength = i;
4992 if (!isASCIIDigit(string[i])) {
4993 if (!decimalMarkSeen && string[i] == '.')
4994 decimalMarkSeen = true;
5000 if (decimalMarkSeen && processedLength == 1)
5003 return processedLength;
5006 // Returns the number of characters consumed for parsing a valid double
5007 // terminated by the given terminator character
5008 template <typename CharacterType>
5009 static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value)
5011 int length = checkForValidDouble(string, end, terminator);
5016 double localValue = 0;
5018 // The consumed characters here are guaranteed to be
5019 // ASCII digits with or without a decimal mark
5020 for (; position < length; ++position) {
5021 if (string[position] == '.')
5023 localValue = localValue * 10 + string[position] - '0';
5026 if (++position == length) {
5031 double fraction = 0;
5034 while (position < length && scale < MAX_SCALE) {
5035 fraction = fraction * 10 + string[position++] - '0';
5039 value = localValue + fraction / scale;
5043 template <typename CharacterType>
5044 static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
5046 const CharacterType* current = string;
5047 double localValue = 0;
5048 bool negative = false;
5049 while (current != end && isHTMLSpace<CharacterType>(*current))
5051 if (current != end && *current == '-') {
5055 if (current == end || !isASCIIDigit(*current))
5057 while (current != end && isASCIIDigit(*current)) {
5058 double newValue = localValue * 10 + *current++ - '0';
5059 if (newValue >= 255) {
5060 // Clamp values at 255.
5062 while (current != end && isASCIIDigit(*current))
5066 localValue = newValue;
5072 if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
5075 if (*current == '.') {
5076 // We already parsed the integral part, try to parse
5077 // the fraction part of the percentage value.
5078 double percentage = 0;
5079 int numCharactersParsed = parseDouble(current, end, '%', percentage);
5080 if (!numCharactersParsed)
5082 current += numCharactersParsed;
5083 if (*current != '%')
5085 localValue += percentage;
5088 if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
5091 if (*current == '%') {
5092 expect = CSSPrimitiveValue::CSS_PERCENTAGE;
5093 localValue = localValue / 100.0 * 256.0;
5094 // Clamp values at 255 for percentages over 100%
5095 if (localValue > 255)
5099 expect = CSSPrimitiveValue::CSS_NUMBER;
5101 while (current != end && isHTMLSpace<CharacterType>(*current))
5103 if (current == end || *current++ != terminator)
5105 // Clamp negative values at zero.
5106 value = negative ? 0 : static_cast<int>(localValue);
5111 template <typename CharacterType>
5112 static inline bool isTenthAlpha(const CharacterType* string, const int length)
5115 if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
5119 if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
5125 template <typename CharacterType>
5126 static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
5128 while (string != end && isHTMLSpace<CharacterType>(*string))
5131 bool negative = false;
5133 if (string != end && *string == '-') {
5140 int length = end - string;
5144 if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
5147 if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
5148 if (checkForValidDouble(string, end, terminator)) {
5149 value = negative ? 0 : 255;
5156 if (length == 2 && string[0] != '.') {
5157 value = !negative && string[0] == '1' ? 255 : 0;
5162 if (isTenthAlpha(string, length - 1)) {
5163 static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
5164 value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
5170 if (!parseDouble(string, end, terminator, alpha))
5172 value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
5177 template <typename CharacterType>
5178 static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
5182 return characters[4] == '('
5183 && isASCIIAlphaCaselessEqual(characters[0], 'r')
5184 && isASCIIAlphaCaselessEqual(characters[1], 'g')
5185 && isASCIIAlphaCaselessEqual(characters[2], 'b')
5186 && isASCIIAlphaCaselessEqual(characters[3], 'a');
5189 template <typename CharacterType>
5190 static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
5194 return characters[3] == '('
5195 && isASCIIAlphaCaselessEqual(characters[0], 'r')
5196 && isASCIIAlphaCaselessEqual(characters[1], 'g')
5197 && isASCIIAlphaCaselessEqual(characters[2], 'b');
5200 template <typename CharacterType>
5201 static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length , bool strict)
5203 CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
5205 if (length >= 4 && characters[0] == '#')
5206 return Color::parseHexColor(characters + 1, length - 1, rgb);
5208 if (!strict && length >= 3) {
5209 if (Color::parseHexColor(characters, length, rgb))
5213 // Try rgba() syntax.
5214 if (mightBeRGBA(characters, length)) {
5215 const CharacterType* current = characters + 5;
5216 const CharacterType* end = characters + length;
5222 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
5224 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
5226 if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
5228 if (!parseAlphaValue(current, end, ')', alpha))
5232 rgb = makeRGBA(red, green, blue, alpha);
5236 // Try rgb() syntax.
5237 if (mightBeRGB(characters, length)) {
5238 const CharacterType* current = characters + 4;
5239 const CharacterType* end = characters + length;
5243 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
5245 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
5247 if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
5251 rgb = makeRGB(red, green, blue);
5258 template<typename StringType>
5259 bool CSSPropertyParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict)
5261 unsigned length = name.length();
5268 parseResult = fastParseColorInternal(rgb, name.characters8(), length, strict);
5270 parseResult = fastParseColorInternal(rgb, name.characters16(), length, strict);
5275 // Try named colors.
5277 if (!tc.setNamedColor(name))
5283 template bool CSSPropertyParser::fastParseColor(RGBA32&, const String&, bool strict);
5285 inline double CSSPropertyParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc)
5287 const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue;
5288 if (releaseCalc == ReleaseParsedCalcValue)
5289 m_parsedCalculation.release();
5293 bool CSSPropertyParser::isCalculation(CSSParserValue* value)
5295 return (value->unit == CSSParserValue::Function)
5296 && (equalIgnoringCase(value->function->name, "calc(")
5297 || equalIgnoringCase(value->function->name, "-webkit-calc(")
5298 || equalIgnoringCase(value->function->name, "-webkit-min(")
5299 || equalIgnoringCase(value->function->name, "-webkit-max("));
5302 inline int CSSPropertyParser::colorIntFromValue(CSSParserValue* v)
5306 if (m_parsedCalculation)
5307 isPercent = m_parsedCalculation->category() == CalcPercent;
5309 isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
5311 const double value = parsedDouble(v, ReleaseParsedCalcValue);
5319 return static_cast<int>(value * 256.0 / 100.0);
5325 return static_cast<int>(value);
5328 bool CSSPropertyParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
5330 CSSParserValueList* args = value->function->args.get();
5331 CSSParserValue* v = args->current();
5332 Units unitType = FUnknown;
5333 // Get the first value and its type
5334 if (validUnit(v, FInteger, HTMLStandardMode))
5335 unitType = FInteger;
5336 else if (validUnit(v, FPercent, HTMLStandardMode))
5337 unitType = FPercent;
5341 colorArray[0] = colorIntFromValue(v);
5342 for (int i = 1; i < 3; i++) {
5344 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5347 if (!validUnit(v, unitType, HTMLStandardMode))
5349 colorArray[i] = colorIntFromValue(v);
5353 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5356 if (!validUnit(v, FNumber, HTMLStandardMode))
5358 const double value = parsedDouble(v, ReleaseParsedCalcValue);
5359 // Convert the floating pointer number of alpha to an integer in the range [0, 256),
5360 // with an equal distribution across all 256 values.
5361 colorArray[3] = static_cast<int>(max(0.0, min(1.0, value)) * nextafter(256.0, 0.0));
5366 // The CSS3 specification defines the format of a HSL color as
5367 // hsl(<number>, <percent>, <percent>)
5368 // and with alpha, the format is
5369 // hsla(<number>, <percent>, <percent>, <number>)
5370 // The first value, HUE, is in an angle with a value between 0 and 360
5371 bool CSSPropertyParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
5373 CSSParserValueList* args = value->function->args.get();
5374 CSSParserValue* v = args->current();
5375 // Get the first value
5376 if (!validUnit(v, FNumber, HTMLStandardMode))
5378 // normalize the Hue value and change it to be between 0 and 1.0
5379 colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0;
5380 for (int i = 1; i < 3; i++) {
5382 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5385 if (!validUnit(v, FPercent, HTMLStandardMode))
5387 colorArray[i] = max(0.0, min(100.0, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0
5391 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5394 if (!validUnit(v, FNumber, HTMLStandardMode))
5396 colorArray[3] = max(0.0, min(1.0, parsedDouble(v, ReleaseParsedCalcValue)));
5401 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseColor(CSSParserValue* value)
5403 RGBA32 c = Color::transparent;
5404 if (!parseColorFromValue(value ? value : m_valueList->current(), c))
5406 return cssValuePool().createColorValue(c);
5409 bool CSSPropertyParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
5411 if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
5412 && value->fValue >= 0. && value->fValue < 1000000.) {
5413 String str = String::format("%06d", static_cast<int>((value->fValue+.5)));
5414 // FIXME: This should be strict parsing for SVG as well.
5415 if (!fastParseColor(c, str, !inQuirksMode()))
5417 } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
5418 value->unit == CSSPrimitiveValue::CSS_IDENT ||
5419 (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
5420 if (!fastParseColor(c, value->string, !inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
5422 } else if (value->unit == CSSParserValue::Function &&
5423 value->function->args != 0 &&
5424 value->function->args->size() == 5 /* rgb + two commas */ &&
5425 equalIgnoringCase(value->function->name, "rgb(")) {
5427 if (!parseColorParameters(value, colorValues, false))
5429 c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
5431 if (value->unit == CSSParserValue::Function &&
5432 value->function->args != 0 &&
5433 value->function->args->size() == 7 /* rgba + three commas */ &&
5434 equalIgnoringCase(value->function->name, "rgba(")) {
5436 if (!parseColorParameters(value, colorValues, true))
5438 c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
5439 } else if (value->unit == CSSParserValue::Function &&
5440 value->function->args != 0 &&
5441 value->function->args->size() == 5 /* hsl + two commas */ &&
5442 equalIgnoringCase(value->function->name, "hsl(")) {
5443 double colorValues[3];
5444 if (!parseHSLParameters(value, colorValues, false))
5446 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
5447 } else if (value->unit == CSSParserValue::Function &&
5448 value->function->args != 0 &&
5449 value->function->args->size() == 7 /* hsla + three commas */ &&
5450 equalIgnoringCase(value->function->name, "hsla(")) {
5451 double colorValues[4];
5452 if (!parseHSLParameters(value, colorValues, true))
5454 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
5462 // This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return)
5463 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
5464 class ShadowParseContext {
5467 ShadowParseContext(CSSPropertyID prop, CSSPropertyParser* parser)
5473 , allowSpread(false)
5475 , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
5480 bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
5484 // Handle the ,, case gracefully by doing nothing.
5485 if (x || y || blur || spread || color || style) {
5487 values = CSSValueList::createCommaSeparated();
5489 // Construct the current shadow value and add it to the list.
5490 values->append(CSSShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
5493 // Now reset for the next shadow value.
5506 allowSpread = false;
5507 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5510 void commitLength(CSSParserValue* v)
5512 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
5521 } else if (allowY) {
5526 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5528 } else if (allowBlur) {
5529 blur = val.release();
5531 allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5532 } else if (allowSpread) {
5533 spread = val.release();
5534 allowSpread = false;
5538 void commitColor(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val)
5547 allowSpread = false;
5548 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5552 void commitStyle(CSSParserValue* v)
5554 style = cssValuePool().createIdentifierValue(v->id);
5560 allowSpread = false;
5565 CSSPropertyID property;
5566 CSSPropertyParser* m_parser;
5568 RefPtrWillBeMember<CSSValueList> values;
5569 RefPtrWillBeMember<CSSPrimitiveValue> x;
5570 RefPtrWillBeMember<CSSPrimitiveValue> y;
5571 RefPtrWillBeMember<CSSPrimitiveValue> blur;
5572 RefPtrWillBeMember<CSSPrimitiveValue> spread;
5573 RefPtrWillBeMember<CSSPrimitiveValue> style;
5574 RefPtrWillBeMember<CSSPrimitiveValue> color;
5581 bool allowStyle; // inset or not.
5585 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId)
5587 ShadowParseContext context(propId, this);
5588 CSSParserValue* val;
5589 while ((val = valueList->current())) {
5590 // Check for a comma break first.
5591 if (val->unit == CSSParserValue::Operator) {
5592 if (val->iValue != ',' || !context.allowBreak) {
5593 // Other operators aren't legal or we aren't done with the current shadow
5594 // value. Treat as invalid.
5597 // The value is good. Commit it.
5598 context.commitValue();
5599 } else if (validUnit(val, FLength, HTMLStandardMode)) {
5600 // We required a length and didn't get one. Invalid.
5601 if (!context.allowLength())
5604 // Blur radius must be non-negative.
5605 if (context.allowBlur && !validUnit(val, FLength | FNonNeg, HTMLStandardMode))
5608 // A length is allowed here. Construct the value and add it.
5609 context.commitLength(val);
5610 } else if (val->id == CSSValueInset) {
5611 if (!context.allowStyle)
5614 context.commitStyle(val);
5616 // The only other type of value that's ok is a color value.
5617 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedColor = nullptr;
5618 bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu
5619 || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode())
5620 || val->id == CSSValueCurrentcolor);
5622 if (!context.allowColor)
5624 parsedColor = cssValuePool().createIdentifierValue(val->id);
5628 // It's not built-in. Try to parse it as a color.
5629 parsedColor = parseColor(val);
5631 if (!parsedColor || !context.allowColor)
5632 return nullptr; // This value is not a color or length and is invalid or
5633 // it is a color, but a color isn't allowed at this point.
5635 context.commitColor(parsedColor.release());
5641 if (context.allowBreak) {
5642 context.commitValue();
5643 if (context.values && context.values->length())
5644 return context.values.release();
5650 bool CSSPropertyParser::parseReflect(CSSPropertyID propId, bool important)
5652 // box-reflect: <direction> <offset> <mask>
5654 // Direction comes first.
5655 CSSParserValue* val = m_valueList->current();
5656 RefPtrWillBeRawPtr<CSSPrimitiveValue> direction = nullptr;
5662 direction = cssValuePool().createIdentifierValue(val->id);
5668 // The offset comes next.
5669 val = m_valueList->next();
5670 RefPtrWillBeRawPtr<CSSPrimitiveValue> offset = nullptr;
5672 offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
5674 if (!validUnit(val, FLength | FPercent))
5676 offset = createPrimitiveNumericValue(val);
5679 // Now for the mask.
5680 RefPtrWillBeRawPtr<CSSValue> mask = nullptr;
5681 val = m_valueList->next();
5683 mask = parseBorderImage(propId);
5688 RefPtrWillBeRawPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction.release(), offset.release(), mask.release());
5689 addProperty(propId, reflectValue.release(), important);
5690 m_valueList->next();
5694 bool CSSPropertyParser::parseFlex(CSSParserValueList* args, bool important)
5696 if (!args || !args->size() || args->size() > 3)
5698 static const double unsetValue = -1;
5699 double flexGrow = unsetValue;
5700 double flexShrink = unsetValue;
5701 RefPtrWillBeRawPtr<CSSPrimitiveValue> flexBasis = nullptr;
5703 while (CSSParserValue* arg = args->current()) {
5704 if (validUnit(arg, FNumber | FNonNeg)) {
5705 if (flexGrow == unsetValue)
5706 flexGrow = arg->fValue;
5707 else if (flexShrink == unsetValue)
5708 flexShrink = arg->fValue;
5709 else if (!arg->fValue) {
5710 // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
5711 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
5713 // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
5716 } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg)))
5717 flexBasis = parseValidPrimitive(arg->id, arg);
5719 // Not a valid arg for flex.
5725 if (flexGrow == unsetValue)
5727 if (flexShrink == unsetValue)
5730 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
5732 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
5733 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
5734 addProperty(CSSPropertyFlexBasis, flexBasis, important);
5738 bool CSSPropertyParser::parseObjectPosition(bool important)
5740 RefPtrWillBeRawPtr<CSSValue> xValue = nullptr;
5741 RefPtrWillBeRawPtr<CSSValue> yValue = nullptr;
5742 parseFillPosition(m_valueList.get(), xValue, yValue);
5743 if (!xValue || !yValue)
5746 CSSPropertyObjectPosition,
5747 createPrimitiveValuePair(toCSSPrimitiveValue(xValue.get()), toCSSPrimitiveValue(yValue.get()), Pair::KeepIdenticalValues),
5752 class BorderImageParseContext {
5755 BorderImageParseContext()
5756 : m_canAdvance(false)
5757 , m_allowCommit(true)
5758 , m_allowImage(true)
5759 , m_allowImageSlice(true)
5760 , m_allowRepeat(true)
5761 , m_allowForwardSlashOperator(false)
5762 , m_requireWidth(false)
5763 , m_requireOutset(false)
5766 bool canAdvance() const { return m_canAdvance; }
5767 void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
5769 bool allowCommit() const { return m_allowCommit; }
5770 bool allowImage() const { return m_allowImage; }
5771 bool allowImageSlice() const { return m_allowImageSlice; }
5772 bool allowRepeat() const { return m_allowRepeat; }
5773 bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; }
5775 bool requireWidth() const { return m_requireWidth; }
5776 bool requireOutset() const { return m_requireOutset; }
5778 void commitImage(PassRefPtrWillBeRawPtr<CSSValue> image)
5781 m_canAdvance = true;
5782 m_allowCommit = true;
5783 m_allowImage = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
5784 m_allowImageSlice = !m_imageSlice;
5785 m_allowRepeat = !m_repeat;
5787 void commitImageSlice(PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> slice)
5789 m_imageSlice = slice;
5790 m_canAdvance = true;
5791 m_allowCommit = m_allowForwardSlashOperator = true;
5792 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
5793 m_allowImage = !m_image;
5794 m_allowRepeat = !m_repeat;
5796 void commitForwardSlashOperator()
5798 m_canAdvance = true;
5799 m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowForwardSlashOperator = false;
5800 if (!m_borderSlice) {
5801 m_requireWidth = true;
5802 m_requireOutset = false;
5804 m_requireOutset = true;
5805 m_requireWidth = false;
5808 void commitBorderWidth(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> slice)
5810 m_borderSlice = slice;
5811 m_canAdvance = true;
5812 m_allowCommit = m_allowForwardSlashOperator = true;
5813 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
5814 m_allowImage = !m_image;
5815 m_allowRepeat = !m_repeat;
5817 void commitBorderOutset(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> outset)
5820 m_canAdvance = true;
5821 m_allowCommit = true;
5822 m_allowImageSlice = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
5823 m_allowImage = !m_image;
5824 m_allowRepeat = !m_repeat;
5826 void commitRepeat(PassRefPtrWillBeRawPtr<CSSValue> repeat)
5829 m_canAdvance = true;
5830 m_allowCommit = true;
5831 m_allowRepeat = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
5832 m_allowImageSlice = !m_imageSlice;
5833 m_allowImage = !m_image;
5836 PassRefPtrWillBeRawPtr<CSSValue> commitCSSValue()
5838 return createBorderImageValue(m_image, m_imageSlice.get(), m_borderSlice.get(), m_outset.get(), m_repeat.get());
5841 void commitMaskBoxImage(CSSPropertyParser* parser, bool important)
5843 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSource, parser, m_image, important);
5844 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSlice, parser, m_imageSlice.get(), important);
5845 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageWidth, parser, m_borderSlice.get(), important);
5846 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageOutset, parser, m_outset.get(), important);
5847 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageRepeat, parser, m_repeat.get(), important);
5850 void commitBorderImage(CSSPropertyParser* parser, bool important)
5852 commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
5853 commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice.get(), important);
5854 commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice.get(), important);
5855 commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset.get(), important);
5856 commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important);
5859 void commitBorderImageProperty(CSSPropertyID propId, CSSPropertyParser* parser, PassRefPtrWillBeRawPtr<CSSValue> value, bool important)
5862 parser->addProperty(propId, value, important);
5864 parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true);
5867 static bool buildFromParser(CSSPropertyParser&, CSSPropertyID, BorderImageParseContext&);
5873 bool m_allowImageSlice;
5875 bool m_allowForwardSlashOperator;
5877 bool m_requireWidth;
5878 bool m_requireOutset;
5880 RefPtrWillBeMember<CSSValue> m_image;
5881 RefPtrWillBeMember<CSSBorderImageSliceValue> m_imageSlice;
5882 RefPtrWillBeMember<CSSPrimitiveValue> m_borderSlice;
5883 RefPtrWillBeMember<CSSPrimitiveValue> m_outset;
5885 RefPtrWillBeMember<CSSValue> m_repeat;
5888 bool BorderImageParseContext::buildFromParser(CSSPropertyParser& parser, CSSPropertyID propId, BorderImageParseContext& context)
5890 CSSPropertyParser::ShorthandScope scope(&parser, propId);
5891 while (CSSParserValue* val = parser.m_valueList->current()) {
5892 context.setCanAdvance(false);
5894 if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(val))
5895 context.commitForwardSlashOperator();
5897 if (!context.canAdvance() && context.allowImage()) {
5898 if (val->unit == CSSPrimitiveValue::CSS_URI) {
5899 context.commitImage(parser.createCSSImageValueWithReferrer(val->string, parser.m_context.completeURL(val->string)));
5900 } else if (isGeneratedImageValue(val)) {
5901 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
5902 if (parser.parseGeneratedImage(parser.m_valueList.get(), value))
5903 context.commitImage(value.release());
5906 } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
5907 RefPtrWillBeRawPtr<CSSValue> value = parser.parseImageSet(parser.m_valueList.get());
5909 context.commitImage(value.release());
5912 } else if (val->id == CSSValueNone)
5913 context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone));
5916 if (!context.canAdvance() && context.allowImageSlice()) {
5917 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> imageSlice = nullptr;
5918 if (parser.parseBorderImageSlice(propId, imageSlice))
5919 context.commitImageSlice(imageSlice.release());
5922 if (!context.canAdvance() && context.allowRepeat()) {
5923 RefPtrWillBeRawPtr<CSSValue> repeat = nullptr;
5924 if (parser.parseBorderImageRepeat(repeat))
5925 context.commitRepeat(repeat.release());
5928 if (!context.canAdvance() && context.requireWidth()) {
5929 RefPtrWillBeRawPtr<CSSPrimitiveValue> borderSlice = nullptr;
5930 if (parser.parseBorderImageWidth(borderSlice))
5931 context.commitBorderWidth(borderSlice.release());
5934 if (!context.canAdvance() && context.requireOutset()) {
5935 RefPtrWillBeRawPtr<CSSPrimitiveValue> borderOutset = nullptr;
5936 if (parser.parseBorderImageOutset(borderOutset))
5937 context.commitBorderOutset(borderOutset.release());
5940 if (!context.canAdvance())
5943 parser.m_valueList->next();
5946 return context.allowCommit();
5949 bool CSSPropertyParser::parseBorderImageShorthand(CSSPropertyID propId, bool important)
5951 BorderImageParseContext context;
5952 if (BorderImageParseContext::buildFromParser(*this, propId, context)) {
5954 case CSSPropertyWebkitMaskBoxImage:
5955 context.commitMaskBoxImage(this, important);
5957 case CSSPropertyBorderImage:
5958 context.commitBorderImage(this, important);
5961 ASSERT_NOT_REACHED();
5968 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBorderImage(CSSPropertyID propId)
5970 BorderImageParseContext context;
5971 if (BorderImageParseContext::buildFromParser(*this, propId, context)) {
5972 return context.commitCSSValue();
5977 static bool isBorderImageRepeatKeyword(int id)
5979 return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
5982 bool CSSPropertyParser::parseBorderImageRepeat(RefPtrWillBeRawPtr<CSSValue>& result)
5984 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstValue = nullptr;
5985 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondValue = nullptr;
5986 CSSParserValue* val = m_valueList->current();
5989 if (isBorderImageRepeatKeyword(val->id))
5990 firstValue = cssValuePool().createIdentifierValue(val->id);
5994 val = m_valueList->next();
5996 if (isBorderImageRepeatKeyword(val->id))
5997 secondValue = cssValuePool().createIdentifierValue(val->id);
5998 else if (!inShorthand()) {
5999 // If we're not parsing a shorthand then we are invalid.
6002 // We need to rewind the value list, so that when its advanced we'll
6003 // end up back at this value.
6004 m_valueList->previous();
6005 secondValue = firstValue;
6008 secondValue = firstValue;
6010 result = createPrimitiveValuePair(firstValue, secondValue);
6014 class BorderImageSliceParseContext {
6017 BorderImageSliceParseContext(CSSPropertyParser* parser)
6019 , m_allowNumber(true)
6021 , m_allowFinalCommit(false)
6025 bool allowNumber() const { return m_allowNumber; }
6026 bool allowFill() const { return m_allowFill; }
6027 bool allowFinalCommit() const { return m_allowFinalCommit; }
6028 CSSPrimitiveValue* top() const { return m_top.get(); }
6030 void commitNumber(CSSParserValue* v)
6032 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
6044 m_allowNumber = !m_left;
6045 m_allowFinalCommit = true;
6048 void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; }
6050 PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
6052 // We need to clone and repeat values for any omissions.
6066 // Now build a rect value to hold all four of our primitive values.
6067 RefPtrWillBeRawPtr<Quad> quad = Quad::create();
6068 quad->setTop(m_top);
6069 quad->setRight(m_right);
6070 quad->setBottom(m_bottom);
6071 quad->setLeft(m_left);
6073 // Make our new border image value now.
6074 return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill);
6078 CSSPropertyParser* m_parser;
6082 bool m_allowFinalCommit;
6084 RefPtrWillBeMember<CSSPrimitiveValue> m_top;
6085 RefPtrWillBeMember<CSSPrimitiveValue> m_right;
6086 RefPtrWillBeMember<CSSPrimitiveValue> m_bottom;
6087 RefPtrWillBeMember<CSSPrimitiveValue> m_left;
6092 bool CSSPropertyParser::parseBorderImageSlice(CSSPropertyID propId, RefPtrWillBeRawPtr<CSSBorderImageSliceValue>& result)
6094 BorderImageSliceParseContext context(this);
6095 CSSParserValue* val;
6096 while ((val = m_valueList->current())) {
6097 // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
6098 if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, HTMLStandardMode)) {
6099 context.commitNumber(val);
6100 } else if (context.allowFill() && val->id == CSSValueFill)
6101 context.commitFill();
6102 else if (!inShorthand()) {
6103 // If we're not parsing a shorthand then we are invalid.
6106 if (context.allowFinalCommit()) {
6107 // We're going to successfully parse, but we don't want to consume this token.
6108 m_valueList->previous();
6112 m_valueList->next();
6115 if (context.allowFinalCommit()) {
6116 // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
6117 // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
6118 if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
6119 context.commitFill();
6121 // Need to fully commit as a single value.
6122 result = context.commitBorderImageSlice();
6129 class BorderImageQuadParseContext {
6132 BorderImageQuadParseContext(CSSPropertyParser* parser)
6134 , m_allowNumber(true)
6135 , m_allowFinalCommit(false)
6138 bool allowNumber() const { return m_allowNumber; }
6139 bool allowFinalCommit() const { return m_allowFinalCommit; }
6140 CSSPrimitiveValue* top() const { return m_top.get(); }
6142 void commitNumber(CSSParserValue* v)
6144 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = nullptr;
6145 if (v->id == CSSValueAuto)
6146 val = cssValuePool().createIdentifierValue(v->id);
6148 val = m_parser->createPrimitiveNumericValue(v);
6161 m_allowNumber = !m_left;
6162 m_allowFinalCommit = true;
6165 void setTop(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val) { m_top = val; }
6167 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> commitBorderImageQuad()
6169 // We need to clone and repeat values for any omissions.
6183 // Now build a quad value to hold all four of our primitive values.
6184 RefPtrWillBeRawPtr<Quad> quad = Quad::create();
6185 quad->setTop(m_top);
6186 quad->setRight(m_right);
6187 quad->setBottom(m_bottom);
6188 quad->setLeft(m_left);
6190 // Make our new value now.
6191 return cssValuePool().createValue(quad.release());
6195 CSSPropertyParser* m_parser;
6198 bool m_allowFinalCommit;
6200 RefPtrWillBeMember<CSSPrimitiveValue> m_top;
6201 RefPtrWillBeMember<CSSPrimitiveValue> m_right;
6202 RefPtrWillBeMember<CSSPrimitiveValue> m_bottom;
6203 RefPtrWillBeMember<CSSPrimitiveValue> m_left;
6206 bool CSSPropertyParser::parseBorderImageQuad(Units validUnits, RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
6208 BorderImageQuadParseContext context(this);
6209 CSSParserValue* val;
6210 while ((val = m_valueList->current())) {
6211 if (context.allowNumber() && (validUnit(val, validUnits, HTMLStandardMode) || val->id == CSSValueAuto)) {
6212 context.commitNumber(val);
6213 } else if (!inShorthand()) {
6214 // If we're not parsing a shorthand then we are invalid.
6217 if (context.allowFinalCommit())
6218 m_valueList->previous(); // The shorthand loop will advance back to this point.
6221 m_valueList->next();
6224 if (context.allowFinalCommit()) {
6225 // Need to fully commit as a single value.
6226 result = context.commitBorderImageQuad();
6232 bool CSSPropertyParser::parseBorderImageWidth(RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
6234 return parseBorderImageQuad(FLength | FNumber | FNonNeg | FPercent, result);
6237 bool CSSPropertyParser::parseBorderImageOutset(RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
6239 return parseBorderImageQuad(FLength | FNumber | FNonNeg, result);
6242 bool CSSPropertyParser::parseBorderRadius(CSSPropertyID propId, bool important)
6244 unsigned num = m_valueList->size();
6248 ShorthandScope scope(this, propId);
6249 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
6251 // Zero initialize the array of raw pointers.
6252 memset(&radii, 0, sizeof(radii));
6255 unsigned indexAfterSlash = 0;
6256 for (unsigned i = 0; i < num; ++i) {
6257 CSSParserValue* value = m_valueList->valueAt(i);
6258 if (value->unit == CSSParserValue::Operator) {
6259 if (value->iValue != '/')
6262 if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
6265 indexAfterSlash = i + 1;
6266 completeBorderRadii(radii[0]);
6270 if (i - indexAfterSlash >= 4)
6273 if (!validUnit(value, FLength | FPercent | FNonNeg))
6276 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
6278 if (!indexAfterSlash) {
6279 radii[0][i] = radius;
6281 // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
6282 if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
6283 indexAfterSlash = 1;
6284 completeBorderRadii(radii[0]);
6287 radii[1][i - indexAfterSlash] = radius.release();
6290 if (!indexAfterSlash) {
6291 completeBorderRadii(radii[0]);
6292 for (unsigned i = 0; i < 4; ++i)
6293 radii[1][i] = radii[0][i];
6295 completeBorderRadii(radii[1]);
6297 ImplicitScope implicitScope(this, PropertyImplicit);
6298 addProperty(CSSPropertyBorderTopLeftRadius, createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()), important);
6299 addProperty(CSSPropertyBorderTopRightRadius, createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()), important);
6300 addProperty(CSSPropertyBorderBottomRightRadius, createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()), important);
6301 addProperty(CSSPropertyBorderBottomLeftRadius, createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()), important);
6305 bool CSSPropertyParser::parseAspectRatio(bool important)
6307 unsigned num = m_valueList->size();
6308 if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
6309 addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(CSSValueNone), important);
6316 CSSParserValue* lvalue = m_valueList->valueAt(0);
6317 CSSParserValue* op = m_valueList->valueAt(1);
6318 CSSParserValue* rvalue = m_valueList->valueAt(2);
6320 if (!isForwardSlashOperator(op))
6323 if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
6326 if (!lvalue->fValue || !rvalue->fValue)
6329 addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important);
6334 bool CSSPropertyParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important)
6336 enum { ID, VAL } state = ID;
6338 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
6339 RefPtrWillBeRawPtr<CSSPrimitiveValue> counterName = nullptr;
6342 CSSParserValue* val = m_valueList->current();
6345 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
6346 counterName = createPrimitiveStringValue(val);
6348 m_valueList->next();
6353 int i = defaultValue;
6354 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
6355 i = clampToInteger(val->fValue);
6356 m_valueList->next();
6359 list->append(createPrimitiveValuePair(counterName.release(),
6360 cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER)));
6368 if (list->length() > 0) {
6369 addProperty(propId, list.release(), important);
6376 // This should go away once we drop support for -webkit-gradient
6377 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
6379 RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
6380 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
6381 if ((equalIgnoringCase(a, "left") && horizontal)
6382 || (equalIgnoringCase(a, "top") && !horizontal))
6383 result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
6384 else if ((equalIgnoringCase(a, "right") && horizontal)
6385 || (equalIgnoringCase(a, "bottom") && !horizontal))
6386 result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
6387 else if (equalIgnoringCase(a, "center"))
6388 result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
6389 } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
6390 result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(a->unit));
6394 bool parseDeprecatedGradientColorStop(CSSPropertyParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
6396 if (a->unit != CSSParserValue::Function)
6399 if (!equalIgnoringCase(a->function->name, "from(") &&
6400 !equalIgnoringCase(a->function->name, "to(") &&
6401 !equalIgnoringCase(a->function->name, "color-stop("))
6404 CSSParserValueList* args = a->function->args.get();
6408 if (equalIgnoringCase(a->function->name, "from(")
6409 || equalIgnoringCase(a->function->name, "to(")) {
6410 // The "from" and "to" stops expect 1 argument.
6411 if (args->size() != 1)
6414 if (equalIgnoringCase(a->function->name, "from("))
6415 stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
6417 stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
6419 CSSValueID id = args->current()->id;
6420 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
6421 stop.m_color = cssValuePool().createIdentifierValue(id);
6423 stop.m_color = p->parseColor(args->current());
6428 // The "color-stop" function expects 3 arguments.
6429 if (equalIgnoringCase(a->function->name, "color-stop(")) {
6430 if (args->size() != 3)
6433 CSSParserValue* stopArg = args->current();
6434 if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
6435 stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
6436 else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
6437 stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
6441 stopArg = args->next();
6442 if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
6445 stopArg = args->next();
6446 CSSValueID id = stopArg->id;
6447 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
6448 stop.m_color = cssValuePool().createIdentifierValue(id);
6450 stop.m_color = p->parseColor(stopArg);
6458 bool CSSPropertyParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient)
6460 // Walk the arguments.
6461 CSSParserValueList* args = valueList->current()->function->args.get();
6462 if (!args || args->size() == 0)
6465 // The first argument is the gradient type. It is an identifier.
6466 CSSGradientType gradientType;
6467 CSSParserValue* a = args->current();
6468 if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
6470 if (equalIgnoringCase(a, "linear"))
6471 gradientType = CSSDeprecatedLinearGradient;
6472 else if (equalIgnoringCase(a, "radial"))
6473 gradientType = CSSDeprecatedRadialGradient;
6477 RefPtrWillBeRawPtr<CSSGradientValue> result = nullptr;
6478 switch (gradientType) {
6479 case CSSDeprecatedLinearGradient:
6480 result = CSSLinearGradientValue::create(NonRepeating, gradientType);
6482 case CSSDeprecatedRadialGradient:
6483 result = CSSRadialGradientValue::create(NonRepeating, gradientType);
6486 // The rest of the gradient types shouldn't appear here.
6487 ASSERT_NOT_REACHED();
6495 // Next comes the starting point for the gradient as an x y pair. There is no
6496 // comma between the x and the y values.
6497 // First X. It can be left, right, number or percent.
6501 RefPtrWillBeRawPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
6504 result->setFirstX(point.release());
6506 // First Y. It can be top, bottom, number or percent.
6510 point = parseDeprecatedGradientPoint(a, false);
6513 result->setFirstY(point.release());
6515 // Comma after the first point.
6520 // For radial gradients only, we now expect a numeric radius.
6521 if (gradientType == CSSDeprecatedRadialGradient) {
6523 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
6525 toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
6527 // Comma after the first radius.
6533 // Next is the ending point for the gradient as an x, y pair.
6534 // Second X. It can be left, right, number or percent.
6538 point = parseDeprecatedGradientPoint(a, true);
6541 result->setSecondX(point.release());
6543 // Second Y. It can be top, bottom, number or percent.
6547 point = parseDeprecatedGradientPoint(a, false);
6550 result->setSecondY(point.release());
6552 // For radial gradients only, we now expect the second radius.
6553 if (gradientType == CSSDeprecatedRadialGradient) {
6554 // Comma after the second point.
6560 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
6562 toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
6565 // We now will accept any number of stops (0 or more).
6568 // Look for the comma before the next stop.
6572 // Now examine the stop itself.
6577 // The function name needs to be one of "from", "to", or "color-stop."
6578 CSSGradientColorStop stop;
6579 if (!parseDeprecatedGradientColorStop(this, a, stop))
6581 result->addStop(stop);
6587 gradient = result.release();
6591 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
6593 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
6599 isHorizontal = true;
6602 case CSSValueBottom:
6603 isHorizontal = false;
6608 return cssValuePool().createIdentifierValue(a->id);
6611 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSPropertyParser* p, CSSParserValue* value)
6613 CSSValueID id = value->id;
6614 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
6615 return cssValuePool().createIdentifierValue(id);
6617 return p->parseColor(value);
6620 bool CSSPropertyParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6622 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient);
6624 // Walk the arguments.
6625 CSSParserValueList* args = valueList->current()->function->args.get();
6626 if (!args || !args->size())
6629 CSSParserValue* a = args->current();
6633 bool expectComma = false;
6635 if (validUnit(a, FAngle, HTMLStandardMode)) {
6636 result->setAngle(createPrimitiveNumericValue(a));
6641 // Look one or two optional keywords that indicate a side or corner.
6642 RefPtrWillBeRawPtr<CSSPrimitiveValue> startX = nullptr;
6643 RefPtrWillBeRawPtr<CSSPrimitiveValue> startY = nullptr;
6645 RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr;
6646 bool isHorizontal = false;
6647 if ((location = valueFromSideKeyword(a, isHorizontal))) {
6653 if ((a = args->next())) {
6654 if ((location = valueFromSideKeyword(a, isHorizontal))) {
6672 if (!startX && !startY)
6673 startY = cssValuePool().createIdentifierValue(CSSValueTop);
6675 result->setFirstX(startX.release());
6676 result->setFirstY(startY.release());
6679 if (!parseGradientColorStops(args, result.get(), expectComma))
6682 if (!result->stopCount())
6685 gradient = result.release();
6689 bool CSSPropertyParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6691 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
6693 // Walk the arguments.
6694 CSSParserValueList* args = valueList->current()->function->args.get();
6695 if (!args || !args->size())
6698 CSSParserValue* a = args->current();
6702 bool expectComma = false;
6704 // Optional background-position
6705 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
6706 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
6707 // parse2ValuesFillPosition advances the args next pointer.
6708 parse2ValuesFillPosition(args, centerX, centerY);
6709 a = args->current();
6713 if (centerX || centerY) {
6723 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
6724 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
6725 // CSS3 radial gradients always share the same start and end point.
6726 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
6727 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
6729 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
6730 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr;
6732 // Optional shape and/or size in any order.
6733 for (int i = 0; i < 2; ++i) {
6734 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
6737 bool foundValue = false;
6739 case CSSValueCircle:
6740 case CSSValueEllipse:
6741 shapeValue = cssValuePool().createIdentifierValue(a->id);
6744 case CSSValueClosestSide:
6745 case CSSValueClosestCorner:
6746 case CSSValueFarthestSide:
6747 case CSSValueFarthestCorner:
6748 case CSSValueContain:
6750 sizeValue = cssValuePool().createIdentifierValue(a->id);
6766 result->setShape(shapeValue);
6767 result->setSizingBehavior(sizeValue);
6769 // Or, two lengths or percentages
6770 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr;
6771 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr;
6773 if (!shapeValue && !sizeValue) {
6774 if (validUnit(a, FLength | FPercent)) {
6775 horizontalSize = createPrimitiveNumericValue(a);
6783 if (validUnit(a, FLength | FPercent)) {
6784 verticalSize = createPrimitiveNumericValue(a);
6793 // Must have neither or both.
6794 if (!horizontalSize != !verticalSize)
6797 result->setEndHorizontalSize(horizontalSize);
6798 result->setEndVerticalSize(verticalSize);
6800 if (!parseGradientColorStops(args, result.get(), expectComma))
6803 gradient = result.release();
6807 bool CSSPropertyParser::parseLinearGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6809 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient);
6811 CSSParserValueList* args = valueList->current()->function->args.get();
6812 if (!args || !args->size())
6815 CSSParserValue* a = args->current();
6819 bool expectComma = false;
6821 if (validUnit(a, FAngle, HTMLStandardMode)) {
6822 result->setAngle(createPrimitiveNumericValue(a));
6826 } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) {
6827 // to [ [left | right] || [top | bottom] ]
6832 RefPtrWillBeRawPtr<CSSPrimitiveValue> endX = nullptr;
6833 RefPtrWillBeRawPtr<CSSPrimitiveValue> endY = nullptr;
6834 RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr;
6835 bool isHorizontal = false;
6837 location = valueFromSideKeyword(a, isHorizontal);
6850 location = valueFromSideKeyword(a, isHorizontal);
6866 result->setFirstX(endX.release());
6867 result->setFirstY(endY.release());
6870 if (!parseGradientColorStops(args, result.get(), expectComma))
6873 if (!result->stopCount())
6876 gradient = result.release();
6880 bool CSSPropertyParser::parseRadialGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6882 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
6884 CSSParserValueList* args = valueList->current()->function->args.get();
6885 if (!args || !args->size())
6888 CSSParserValue* a = args->current();
6892 bool expectComma = false;
6894 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
6895 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr;
6896 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr;
6897 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr;
6899 // First part of grammar, the size/shape clause:
6900 // [ circle || <length> ] |
6901 // [ ellipse || [ <length> | <percentage> ]{2} ] |
6902 // [ [ circle | ellipse] || <size-keyword> ]
6903 for (int i = 0; i < 3; ++i) {
6904 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
6905 bool badIdent = false;
6907 case CSSValueCircle:
6908 case CSSValueEllipse:
6911 shapeValue = cssValuePool().createIdentifierValue(a->id);
6913 case CSSValueClosestSide:
6914 case CSSValueClosestCorner:
6915 case CSSValueFarthestSide:
6916 case CSSValueFarthestCorner:
6917 if (sizeValue || horizontalSize)
6919 sizeValue = cssValuePool().createIdentifierValue(a->id);
6931 } else if (validUnit(a, FLength | FPercent)) {
6933 if (sizeValue || horizontalSize)
6935 horizontalSize = createPrimitiveNumericValue(a);
6941 if (validUnit(a, FLength | FPercent)) {
6942 verticalSize = createPrimitiveNumericValue(a);
6952 // You can specify size as a keyword or a length/percentage, not both.
6953 if (sizeValue && horizontalSize)
6955 // Circles must have 0 or 1 lengths.
6956 if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize)
6958 // Ellipses must have 0 or 2 length/percentages.
6959 if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
6961 // If there's only one size, it must be a length.
6962 if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
6965 result->setShape(shapeValue);
6966 result->setSizingBehavior(sizeValue);
6967 result->setEndHorizontalSize(horizontalSize);
6968 result->setEndVerticalSize(verticalSize);
6970 // Second part of grammar, the center-position clause:
6972 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
6973 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
6974 if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) {
6979 parseFillPosition(args, centerX, centerY);
6980 if (!(centerX && centerY))
6983 a = args->current();
6986 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
6987 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
6988 // Right now, CSS radial gradients have the same start and end centers.
6989 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
6990 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
6993 if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
6996 if (!parseGradientColorStops(args, result.get(), expectComma))
6999 gradient = result.release();
7003 bool CSSPropertyParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
7005 CSSParserValue* a = valueList->current();
7007 // Now look for color stops.
7009 // Look for the comma before the next stop.
7014 a = valueList->next();
7019 // <color-stop> = <color> [ <percentage> | <length> ]?
7020 CSSGradientColorStop stop;
7021 stop.m_color = parseGradientColorOrKeyword(this, a);
7025 a = valueList->next();
7027 if (validUnit(a, FLength | FPercent)) {
7028 stop.m_position = createPrimitiveNumericValue(a);
7029 a = valueList->next();
7033 gradient->addStop(stop);
7037 // Must have 2 or more stops to be valid.
7038 return gradient->stopCount() >= 2;
7041 bool CSSPropertyParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value)
7043 CSSParserValue* val = valueList->current();
7045 if (val->unit != CSSParserValue::Function)
7048 if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) {
7049 // FIXME: This should send a deprecation message.
7050 if (m_context.useCounter())
7051 m_context.useCounter()->count(UseCounter::DeprecatedWebKitGradient);
7052 return parseDeprecatedGradient(valueList, value);
7055 if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")) {
7056 // FIXME: This should send a deprecation message.
7057 if (m_context.useCounter())
7058 m_context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGradient);
7059 return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
7062 if (equalIgnoringCase(val->function->name, "linear-gradient("))
7063 return parseLinearGradient(valueList, value, NonRepeating);
7065 if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")) {
7066 // FIXME: This should send a deprecation message.
7067 if (m_context.useCounter())
7068 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLinearGradient);
7069 return parseDeprecatedLinearGradient(valueList, value, Repeating);
7072 if (equalIgnoringCase(val->function->name, "repeating-linear-gradient("))
7073 return parseLinearGradient(valueList, value, Repeating);
7075 if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")) {
7076 // FIXME: This should send a deprecation message.
7077 if (m_context.useCounter())
7078 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGradient);
7079 return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
7082 if (equalIgnoringCase(val->function->name, "radial-gradient("))
7083 return parseRadialGradient(valueList, value, NonRepeating);
7085 if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")) {
7086 if (m_context.useCounter())
7087 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingRadialGradient);
7088 return parseDeprecatedRadialGradient(valueList, value, Repeating);
7091 if (equalIgnoringCase(val->function->name, "repeating-radial-gradient("))
7092 return parseRadialGradient(valueList, value, Repeating);
7094 if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
7095 return parseCanvas(valueList, value);
7097 if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
7098 return parseCrossfade(valueList, value);
7103 bool CSSPropertyParser::parseCrossfade(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& crossfade)
7105 // Walk the arguments.
7106 CSSParserValueList* args = valueList->current()->function->args.get();
7107 if (!args || args->size() != 5)
7109 CSSParserValue* a = args->current();
7110 RefPtrWillBeRawPtr<CSSValue> fromImageValue = nullptr;
7111 RefPtrWillBeRawPtr<CSSValue> toImageValue = nullptr;
7113 // The first argument is the "from" image. It is a fill image.
7114 if (!a || !parseFillImage(args, fromImageValue))
7123 // The second argument is the "to" image. It is a fill image.
7124 if (!a || !parseFillImage(args, toImageValue))
7133 // The third argument is the crossfade value. It is a percentage or a fractional number.
7134 RefPtrWillBeRawPtr<CSSPrimitiveValue> percentage = nullptr;
7138 if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7139 percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
7140 else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
7141 percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
7145 RefPtrWillBeRawPtr<CSSCrossfadeValue> result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
7146 result->setPercentage(percentage);
7153 bool CSSPropertyParser::parseCanvas(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& canvas)
7155 // Walk the arguments.
7156 CSSParserValueList* args = valueList->current()->function->args.get();
7157 if (!args || args->size() != 1)
7160 // The first argument is the canvas name. It is an identifier.
7161 CSSParserValue* value = args->current();
7162 if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
7165 canvas = CSSCanvasValue::create(value->string);
7169 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseImageSet(CSSParserValueList* valueList)
7171 CSSParserValue* function = valueList->current();
7173 if (function->unit != CSSParserValue::Function)
7176 CSSParserValueList* functionArgs = valueList->current()->function->args.get();
7177 if (!functionArgs || !functionArgs->size() || !functionArgs->current())
7180 RefPtrWillBeRawPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
7182 CSSParserValue* arg = functionArgs->current();
7184 if (arg->unit != CSSPrimitiveValue::CSS_URI)
7187 RefPtrWillBeRawPtr<CSSValue> image = createCSSImageValueWithReferrer(arg->string, completeURL(arg->string));
7188 imageSet->append(image);
7190 arg = functionArgs->next();
7191 if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
7194 double imageScaleFactor = 0;
7195 const String& string = arg->string;
7196 unsigned length = string.length();
7199 if (string.is8Bit()) {
7200 const LChar* start = string.characters8();
7201 parseDouble(start, start + length, 'x', imageScaleFactor);
7203 const UChar* start = string.characters16();
7204 parseDouble(start, start + length, 'x', imageScaleFactor);
7206 if (imageScaleFactor <= 0)
7208 imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER));
7210 // If there are no more arguments, we're done.
7211 arg = functionArgs->next();
7215 // If there are more arguments, they should be after a comma.
7219 // Skip the comma and move on to the next argument.
7220 arg = functionArgs->next();
7223 return imageSet.release();
7226 bool CSSPropertyParser::parseWillChange(bool important)
7228 ASSERT(RuntimeEnabledFeatures::cssWillChangeEnabled());
7230 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
7231 if (m_valueList->current()->id == CSSValueAuto) {
7232 if (m_valueList->next())
7236 CSSParserValue* currentValue;
7237 bool expectComma = false;
7239 // Every comma-separated list of CSS_IDENTs is a valid will-change value,
7240 // unless the list includes an explicitly disallowed CSS_IDENT.
7241 while ((currentValue = m_valueList->current())) {
7243 if (!isComma(currentValue))
7245 expectComma = false;
7246 m_valueList->next();
7250 if (currentValue->unit != CSSPrimitiveValue::CSS_IDENT)
7253 CSSPropertyID property = cssPropertyID(currentValue->string);
7254 if (property && RuntimeCSSEnabled::isCSSPropertyEnabled(property)) {
7255 if (property == CSSPropertyWillChange)
7257 values->append(cssValuePool().createIdentifierValue(property));
7259 switch (currentValue->id) {
7263 case CSSValueDefault:
7264 case CSSValueInitial:
7265 case CSSValueInherit:
7267 case CSSValueContents:
7268 case CSSValueScrollPosition:
7269 values->append(cssValuePool().createIdentifierValue(currentValue->id));
7276 m_valueList->next();
7279 addProperty(CSSPropertyWillChange, values.release(), important);
7283 static void filterInfoForName(const CSSParserString& name, CSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
7285 if (equalIgnoringCase(name, "grayscale("))
7286 filterType = CSSFilterValue::GrayscaleFilterOperation;
7287 else if (equalIgnoringCase(name, "sepia("))
7288 filterType = CSSFilterValue::SepiaFilterOperation;
7289 else if (equalIgnoringCase(name, "saturate("))
7290 filterType = CSSFilterValue::SaturateFilterOperation;
7291 else if (equalIgnoringCase(name, "hue-rotate("))
7292 filterType = CSSFilterValue::HueRotateFilterOperation;
7293 else if (equalIgnoringCase(name, "invert("))
7294 filterType = CSSFilterValue::InvertFilterOperation;
7295 else if (equalIgnoringCase(name, "opacity("))
7296 filterType = CSSFilterValue::OpacityFilterOperation;
7297 else if (equalIgnoringCase(name, "brightness("))
7298 filterType = CSSFilterValue::BrightnessFilterOperation;
7299 else if (equalIgnoringCase(name, "contrast("))
7300 filterType = CSSFilterValue::ContrastFilterOperation;
7301 else if (equalIgnoringCase(name, "blur("))
7302 filterType = CSSFilterValue::BlurFilterOperation;
7303 else if (equalIgnoringCase(name, "drop-shadow(")) {
7304 filterType = CSSFilterValue::DropShadowFilterOperation;
7305 maximumArgumentCount = 4; // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
7309 PassRefPtrWillBeRawPtr<CSSFilterValue> CSSPropertyParser::parseBuiltinFilterArguments(CSSParserValueList* args, CSSFilterValue::FilterOperationType filterType)
7311 RefPtrWillBeRawPtr<CSSFilterValue> filterValue = CSSFilterValue::create(filterType);
7314 switch (filterType) {
7315 case CSSFilterValue::GrayscaleFilterOperation:
7316 case CSSFilterValue::SepiaFilterOperation:
7317 case CSSFilterValue::SaturateFilterOperation:
7318 case CSSFilterValue::InvertFilterOperation:
7319 case CSSFilterValue::OpacityFilterOperation:
7320 case CSSFilterValue::ContrastFilterOperation: {
7321 // One optional argument, 0-1 or 0%-100%, if missing use 100%.
7322 if (args->size() > 1)
7326 CSSParserValue* value = args->current();
7327 if (!validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode))
7330 double amount = value->fValue;
7332 // Saturate and Contrast allow values over 100%.
7333 if (filterType != CSSFilterValue::SaturateFilterOperation
7334 && filterType != CSSFilterValue::ContrastFilterOperation) {
7335 double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
7336 if (amount > maxAllowed)
7340 filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
7344 case CSSFilterValue::BrightnessFilterOperation: {
7345 // One optional argument, if missing use 100%.
7346 if (args->size() > 1)
7350 CSSParserValue* value = args->current();
7351 if (!validUnit(value, FNumber | FPercent, HTMLStandardMode))
7354 filterValue->append(cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
7358 case CSSFilterValue::HueRotateFilterOperation: {
7359 // hue-rotate() takes one optional angle.
7360 if (args->size() > 1)
7364 CSSParserValue* argument = args->current();
7365 if (!validUnit(argument, FAngle, HTMLStandardMode))
7368 filterValue->append(createPrimitiveNumericValue(argument));
7372 case CSSFilterValue::BlurFilterOperation: {
7373 // Blur takes a single length. Zero parameters are allowed.
7374 if (args->size() > 1)
7378 CSSParserValue* argument = args->current();
7379 if (!validUnit(argument, FLength | FNonNeg, HTMLStandardMode))
7382 filterValue->append(createPrimitiveNumericValue(argument));
7386 case CSSFilterValue::DropShadowFilterOperation: {
7387 // drop-shadow() takes a single shadow.
7388 RefPtrWillBeRawPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter);
7389 if (!shadowValueList || shadowValueList->length() != 1)
7392 filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0));
7396 ASSERT_NOT_REACHED();
7398 return filterValue.release();
7401 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFilter()
7406 // The filter is a list of functional primitives that specify individual operations.
7407 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7408 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7409 if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function))
7412 CSSFilterValue::FilterOperationType filterType = CSSFilterValue::UnknownFilterOperation;
7414 // See if the specified primitive is one we understand.
7415 if (value->unit == CSSPrimitiveValue::CSS_URI) {
7416 RefPtrWillBeRawPtr<CSSFilterValue> referenceFilterValue = CSSFilterValue::create(CSSFilterValue::ReferenceFilterOperation);
7417 list->append(referenceFilterValue);
7418 referenceFilterValue->append(CSSSVGDocumentValue::create(value->string));
7420 const CSSParserString name = value->function->name;
7421 unsigned maximumArgumentCount = 1;
7423 filterInfoForName(name, filterType, maximumArgumentCount);
7425 if (filterType == CSSFilterValue::UnknownFilterOperation)
7428 CSSParserValueList* args = value->function->args.get();
7432 RefPtrWillBeRawPtr<CSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType);
7436 list->append(filterValue);
7440 return list.release();
7442 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseTransformOrigin()
7444 CSSParserValue* value = m_valueList->current();
7445 CSSValueID id = value->id;
7446 RefPtrWillBeRawPtr<CSSValue> xValue = nullptr;
7447 RefPtrWillBeRawPtr<CSSValue> yValue = nullptr;
7448 RefPtrWillBeRawPtr<CSSValue> zValue = nullptr;
7449 if (id == CSSValueLeft || id == CSSValueRight) {
7450 xValue = cssValuePool().createIdentifierValue(id);
7451 } else if (id == CSSValueTop || id == CSSValueBottom) {
7452 yValue = cssValuePool().createIdentifierValue(id);
7453 } else if (id == CSSValueCenter) {
7454 // Unresolved as to whether this is X or Y.
7455 } else if (validUnit(value, FPercent | FLength)) {
7456 xValue = createPrimitiveNumericValue(value);
7461 if ((value = m_valueList->next())) {
7463 if (!xValue && (id == CSSValueLeft || id == CSSValueRight)) {
7464 xValue = cssValuePool().createIdentifierValue(id);
7465 } else if (!yValue && (id == CSSValueTop || id == CSSValueBottom)) {
7466 yValue = cssValuePool().createIdentifierValue(id);
7467 } else if (id == CSSValueCenter) {
7469 } else if (!yValue && validUnit(value, FPercent | FLength)) {
7470 yValue = createPrimitiveNumericValue(value);
7475 // If X or Y have not been resolved, they must be center.
7477 xValue = cssValuePool().createIdentifierValue(CSSValueCenter);
7479 yValue = cssValuePool().createIdentifierValue(CSSValueCenter);
7481 if ((value = m_valueList->next())) {
7482 if (!validUnit(value, FLength))
7484 zValue = createPrimitiveNumericValue(value);
7486 if ((value = m_valueList->next()))
7489 } else if (!xValue) {
7491 xValue = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
7493 xValue = cssValuePool().createIdentifierValue(CSSValueCenter);
7497 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7498 list->append(xValue.release());
7500 list->append(yValue.release());
7502 list->append(zValue.release());
7503 return list.release();
7506 bool CSSPropertyParser::parseWebkitTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtrWillBeRawPtr<CSSValue>& value, RefPtrWillBeRawPtr<CSSValue>& value2, RefPtrWillBeRawPtr<CSSValue>& value3)
7511 if (propId == CSSPropertyWebkitTransformOrigin) {
7512 propId1 = CSSPropertyWebkitTransformOriginX;
7513 propId2 = CSSPropertyWebkitTransformOriginY;
7514 propId3 = CSSPropertyWebkitTransformOriginZ;
7518 case CSSPropertyWebkitTransformOrigin:
7519 if (!parseWebkitTransformOriginShorthand(value, value2, value3))
7521 // parseWebkitTransformOriginShorthand advances the m_valueList pointer
7523 case CSSPropertyWebkitTransformOriginX: {
7524 value = parseFillPositionX(m_valueList.get());
7526 m_valueList->next();
7529 case CSSPropertyWebkitTransformOriginY: {
7530 value = parseFillPositionY(m_valueList.get());
7532 m_valueList->next();
7535 case CSSPropertyWebkitTransformOriginZ: {
7536 if (validUnit(m_valueList->current(), FLength))
7537 value = createPrimitiveNumericValue(m_valueList->current());
7539 m_valueList->next();
7543 ASSERT_NOT_REACHED();
7550 bool CSSPropertyParser::parseWebkitPerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtrWillBeRawPtr<CSSValue>& value, RefPtrWillBeRawPtr<CSSValue>& value2)
7554 if (propId == CSSPropertyWebkitPerspectiveOrigin) {
7555 propId1 = CSSPropertyWebkitPerspectiveOriginX;
7556 propId2 = CSSPropertyWebkitPerspectiveOriginY;
7560 case CSSPropertyWebkitPerspectiveOrigin:
7561 if (m_valueList->size() > 2)
7563 parse2ValuesFillPosition(m_valueList.get(), value, value2);
7565 case CSSPropertyWebkitPerspectiveOriginX: {
7566 value = parseFillPositionX(m_valueList.get());
7568 m_valueList->next();
7571 case CSSPropertyWebkitPerspectiveOriginY: {
7572 value = parseFillPositionY(m_valueList.get());
7574 m_valueList->next();
7578 ASSERT_NOT_REACHED();
7585 bool CSSPropertyParser::parseTouchAction(bool important)
7587 if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
7590 CSSParserValue* value = m_valueList->current();
7591 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7592 if (m_valueList->size() == 1 && value && (value->id == CSSValueAuto || value->id == CSSValueNone || value->id == CSSValueManipulation)) {
7593 list->append(cssValuePool().createIdentifierValue(value->id));
7594 addProperty(CSSPropertyTouchAction, list.release(), important);
7595 m_valueList->next();
7599 bool isValid = true;
7600 while (isValid && value) {
7601 switch (value->id) {
7603 case CSSValuePanY: {
7604 RefPtrWillBeRawPtr<CSSValue> panValue = cssValuePool().createIdentifierValue(value->id);
7605 if (list->hasValue(panValue.get())) {
7609 list->append(panValue.release());
7617 value = m_valueList->next();
7620 if (list->length() && isValid) {
7621 addProperty(CSSPropertyTouchAction, list.release(), important);
7628 void CSSPropertyParser::addTextDecorationProperty(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important)
7630 // The text-decoration-line property takes priority over text-decoration, unless the latter has important priority set.
7631 if (propId == CSSPropertyTextDecoration && !important && !inShorthand()) {
7632 for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
7633 if (m_parsedProperties[i].id() == CSSPropertyTextDecorationLine)
7637 addProperty(propId, value, important);
7640 bool CSSPropertyParser::parseTextDecoration(CSSPropertyID propId, bool important)
7642 if (propId == CSSPropertyTextDecorationLine
7643 && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
7646 CSSParserValue* value = m_valueList->current();
7647 if (value && value->id == CSSValueNone) {
7648 addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
7649 m_valueList->next();
7653 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7654 bool isValid = true;
7655 while (isValid && value) {
7656 switch (value->id) {
7657 case CSSValueUnderline:
7658 case CSSValueOverline:
7659 case CSSValueLineThrough:
7661 list->append(cssValuePool().createIdentifierValue(value->id));
7668 value = m_valueList->next();
7671 // Values are either valid or in shorthand scope.
7672 if (list->length() && (isValid || inShorthand())) {
7673 addTextDecorationProperty(propId, list.release(), important);
7680 bool CSSPropertyParser::parseTextUnderlinePosition(bool important)
7682 // The text-underline-position property has syntax "auto | [ under || [ left | right ] ]".
7683 // However, values 'left' and 'right' are not implemented yet, so we will parse syntax
7684 // "auto | under" for now.
7685 CSSParserValue* value = m_valueList->current();
7686 switch (value->id) {
7689 if (m_valueList->next())
7691 addProperty(CSSPropertyTextUnderlinePosition, cssValuePool().createIdentifierValue(value->id), important);
7698 bool CSSPropertyParser::parseTextEmphasisStyle(bool important)
7700 unsigned valueListSize = m_valueList->size();
7702 RefPtrWillBeRawPtr<CSSPrimitiveValue> fill = nullptr;
7703 RefPtrWillBeRawPtr<CSSPrimitiveValue> shape = nullptr;
7705 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7706 if (value->unit == CSSPrimitiveValue::CSS_STRING) {
7707 if (fill || shape || (valueListSize != 1 && !inShorthand()))
7709 addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important);
7710 m_valueList->next();
7714 if (value->id == CSSValueNone) {
7715 if (fill || shape || (valueListSize != 1 && !inShorthand()))
7717 addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important);
7718 m_valueList->next();
7722 if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
7725 fill = cssValuePool().createIdentifierValue(value->id);
7726 } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
7729 shape = cssValuePool().createIdentifierValue(value->id);
7730 } else if (!inShorthand())
7736 if (fill && shape) {
7737 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
7738 parsedValues->append(fill.release());
7739 parsedValues->append(shape.release());
7740 addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
7744 addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
7748 addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
7755 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTextIndent()
7757 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7759 bool hasLengthOrPercentage = false;
7760 bool hasEachLine = false;
7761 bool hasHanging = false;
7763 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7764 // <length> | <percentage> | inherit when RuntimeEnabledFeatures::css3TextEnabled() returns false
7765 if (!hasLengthOrPercentage && validUnit(value, FLength | FPercent)) {
7766 list->append(createPrimitiveNumericValue(value));
7767 hasLengthOrPercentage = true;
7771 // [ <length> | <percentage> ] && hanging? && each-line? | inherit
7772 // when RuntimeEnabledFeatures::css3TextEnabled() returns true
7773 if (RuntimeEnabledFeatures::css3TextEnabled()) {
7774 if (!hasEachLine && value->id == CSSValueEachLine) {
7775 list->append(cssValuePool().createIdentifierValue(CSSValueEachLine));
7779 if (!hasHanging && value->id == CSSValueHanging) {
7780 list->append(cssValuePool().createIdentifierValue(CSSValueHanging));
7788 if (!hasLengthOrPercentage)
7791 return list.release();
7794 bool CSSPropertyParser::parseLineBoxContain(bool important)
7796 LineBoxContain lineBoxContain = LineBoxContainNone;
7798 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7799 if (value->id == CSSValueBlock) {
7800 if (lineBoxContain & LineBoxContainBlock)
7802 lineBoxContain |= LineBoxContainBlock;
7803 } else if (value->id == CSSValueInline) {
7804 if (lineBoxContain & LineBoxContainInline)
7806 lineBoxContain |= LineBoxContainInline;
7807 } else if (value->id == CSSValueFont) {
7808 if (lineBoxContain & LineBoxContainFont)
7810 lineBoxContain |= LineBoxContainFont;
7811 } else if (value->id == CSSValueGlyphs) {
7812 if (lineBoxContain & LineBoxContainGlyphs)
7814 lineBoxContain |= LineBoxContainGlyphs;
7815 } else if (value->id == CSSValueReplaced) {
7816 if (lineBoxContain & LineBoxContainReplaced)
7818 lineBoxContain |= LineBoxContainReplaced;
7819 } else if (value->id == CSSValueInlineBox) {
7820 if (lineBoxContain & LineBoxContainInlineBox)
7822 lineBoxContain |= LineBoxContainInlineBox;
7827 if (!lineBoxContain)
7830 addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
7834 bool CSSPropertyParser::parseFontFeatureTag(CSSValueList* settings)
7836 // Feature tag name consists of 4-letter characters.
7837 static const unsigned tagNameLength = 4;
7839 CSSParserValue* value = m_valueList->current();
7840 // Feature tag name comes first
7841 if (value->unit != CSSPrimitiveValue::CSS_STRING)
7843 if (value->string.length() != tagNameLength)
7845 for (unsigned i = 0; i < tagNameLength; ++i) {
7846 // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
7847 UChar character = value->string[i];
7848 if (character < 0x20 || character > 0x7E)
7852 AtomicString tag = value->string;
7854 // Feature tag values could follow: <integer> | on | off
7855 value = m_valueList->next();
7857 if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
7858 tagValue = clampToInteger(value->fValue);
7861 m_valueList->next();
7862 } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
7863 tagValue = value->id == CSSValueOn;
7864 m_valueList->next();
7867 settings->append(CSSFontFeatureValue::create(tag, tagValue));
7871 bool CSSPropertyParser::parseFontFeatureSettings(bool important)
7873 if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) {
7874 RefPtrWillBeRawPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal);
7875 m_valueList->next();
7876 addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
7880 RefPtrWillBeRawPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
7881 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7882 if (!parseFontFeatureTag(settings.get()))
7885 // If the list isn't parsed fully, the current value should be comma.
7886 value = m_valueList->current();
7887 if (value && !isComma(value))
7890 if (settings->length()) {
7891 addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important);
7897 bool CSSPropertyParser::parseFontVariantLigatures(bool important)
7899 RefPtrWillBeRawPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
7900 bool sawCommonLigaturesValue = false;
7901 bool sawDiscretionaryLigaturesValue = false;
7902 bool sawHistoricalLigaturesValue = false;
7903 bool sawContextualLigaturesValue = false;
7905 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7906 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
7909 switch (value->id) {
7910 case CSSValueNoCommonLigatures:
7911 case CSSValueCommonLigatures:
7912 if (sawCommonLigaturesValue)
7914 sawCommonLigaturesValue = true;
7915 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
7917 case CSSValueNoDiscretionaryLigatures:
7918 case CSSValueDiscretionaryLigatures:
7919 if (sawDiscretionaryLigaturesValue)
7921 sawDiscretionaryLigaturesValue = true;
7922 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
7924 case CSSValueNoHistoricalLigatures:
7925 case CSSValueHistoricalLigatures:
7926 if (sawHistoricalLigaturesValue)
7928 sawHistoricalLigaturesValue = true;
7929 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
7931 case CSSValueNoContextual:
7932 case CSSValueContextual:
7933 if (sawContextualLigaturesValue)
7935 sawContextualLigaturesValue = true;
7936 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
7943 if (!ligatureValues->length())
7946 addProperty(CSSPropertyFontVariantLigatures, ligatureValues.release(), important);
7950 bool CSSPropertyParser::parseCalculation(CSSParserValue* value, ValueRange range)
7952 ASSERT(isCalculation(value));
7954 CSSParserValueList* args = value->function->args.get();
7955 if (!args || !args->size())
7958 ASSERT(!m_parsedCalculation);
7959 m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
7961 if (!m_parsedCalculation)
7967 bool CSSPropertyParser::parseViewportProperty(CSSPropertyID propId, bool important)
7969 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
7971 CSSParserValue* value = m_valueList->current();
7975 CSSValueID id = value->id;
7976 bool validPrimitive = false;
7979 case CSSPropertyMinWidth: // auto | extend-to-zoom | <length> | <percentage>
7980 case CSSPropertyMaxWidth:
7981 case CSSPropertyMinHeight:
7982 case CSSPropertyMaxHeight:
7983 if (id == CSSValueAuto || id == CSSValueInternalExtendToZoom)
7984 validPrimitive = true;
7986 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
7988 case CSSPropertyWidth: // shorthand
7989 return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMaxWidth, important);
7990 case CSSPropertyHeight:
7991 return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyMaxHeight, important);
7992 case CSSPropertyMinZoom: // auto | <number> | <percentage>
7993 case CSSPropertyMaxZoom:
7994 case CSSPropertyZoom:
7995 if (id == CSSValueAuto)
7996 validPrimitive = true;
7998 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg));
8000 case CSSPropertyUserZoom: // zoom | fixed
8001 if (id == CSSValueZoom || id == CSSValueFixed)
8002 validPrimitive = true;
8004 case CSSPropertyOrientation: // auto | portrait | landscape
8005 if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandscape)
8006 validPrimitive = true;
8011 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
8012 if (validPrimitive) {
8013 parsedValue = parseValidPrimitive(id, value);
8014 m_valueList->next();
8018 if (!m_valueList->current() || inShorthand()) {
8019 addProperty(propId, parsedValue.release(), important);
8027 bool CSSPropertyParser::parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first, CSSPropertyID second, bool important)
8029 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
8030 unsigned numValues = m_valueList->size();
8035 ShorthandScope scope(this, propId);
8037 if (!parseViewportProperty(first, important))
8040 // If just one value is supplied, the second value
8041 // is implicitly initialized with the first value.
8043 m_valueList->previous();
8045 return parseViewportProperty(second, important);
8048 template <typename CharacterType>
8049 static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
8051 char buffer[maxCSSPropertyNameLength + 1]; // 1 for null character
8053 for (unsigned i = 0; i != length; ++i) {
8054 CharacterType c = propertyName[i];
8055 if (c == 0 || c >= 0x7F)
8056 return CSSPropertyInvalid; // illegal character
8057 buffer[i] = toASCIILower(c);
8059 buffer[length] = '\0';
8061 const char* name = buffer;
8062 const Property* hashTableEntry = findProperty(name, length);
8063 return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
8066 CSSPropertyID cssPropertyID(const String& string)
8068 unsigned length = string.length();
8071 return CSSPropertyInvalid;
8072 if (length > maxCSSPropertyNameLength)
8073 return CSSPropertyInvalid;
8075 return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
8078 CSSPropertyID cssPropertyID(const CSSParserString& string)
8080 unsigned length = string.length();
8083 return CSSPropertyInvalid;
8084 if (length > maxCSSPropertyNameLength)
8085 return CSSPropertyInvalid;
8087 return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
8090 template <typename CharacterType>
8091 static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
8093 char buffer[maxCSSValueKeywordLength + 1]; // 1 for null character
8095 for (unsigned i = 0; i != length; ++i) {
8096 CharacterType c = valueKeyword[i];
8097 if (c == 0 || c >= 0x7F)
8098 return CSSValueInvalid; // illegal character
8099 buffer[i] = WTF::toASCIILower(c);
8101 buffer[length] = '\0';
8103 const Value* hashTableEntry = findValue(buffer, length);
8104 return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSValueInvalid;
8107 CSSValueID cssValueKeywordID(const CSSParserString& string)
8109 unsigned length = string.length();
8111 return CSSValueInvalid;
8112 if (length > maxCSSValueKeywordLength)
8113 return CSSValueInvalid;
8115 return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
8118 bool isValidNthToken(const CSSParserString& token)
8120 // The tokenizer checks for the construct of an+b.
8121 // However, since the {ident} rule precedes the {nth} rule, some of those
8122 // tokens are identified as string literal. Furthermore we need to accept
8123 // "odd" and "even" which does not match to an+b.
8124 return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
8125 || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");
8128 bool CSSPropertyParser::isSystemColor(int id)
8130 return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu;
8133 bool CSSPropertyParser::parseSVGValue(CSSPropertyID propId, bool important)
8135 CSSParserValue* value = m_valueList->current();
8139 CSSValueID id = value->id;
8141 bool validPrimitive = false;
8142 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
8145 /* The comment to the right defines all valid value of these
8146 * properties as defined in SVG 1.1, Appendix N. Property index */
8147 case CSSPropertyAlignmentBaseline:
8148 // auto | baseline | before-edge | text-before-edge | middle |
8149 // central | after-edge | text-after-edge | ideographic | alphabetic |
8150 // hanging | mathematical | inherit
8151 if (id == CSSValueAuto || id == CSSValueBaseline || id == CSSValueMiddle
8152 || (id >= CSSValueBeforeEdge && id <= CSSValueMathematical))
8153 validPrimitive = true;
8156 case CSSPropertyBaselineShift:
8157 // baseline | super | sub | <percentage> | <length> | inherit
8158 if (id == CSSValueBaseline || id == CSSValueSub
8159 || id >= CSSValueSuper)
8160 validPrimitive = true;
8162 validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
8165 case CSSPropertyDominantBaseline:
8166 // auto | use-script | no-change | reset-size | ideographic |
8167 // alphabetic | hanging | mathematical | central | middle |
8168 // text-after-edge | text-before-edge | inherit
8169 if (id == CSSValueAuto || id == CSSValueMiddle
8170 || (id >= CSSValueUseScript && id <= CSSValueResetSize)
8171 || (id >= CSSValueCentral && id <= CSSValueMathematical))
8172 validPrimitive = true;
8175 case CSSPropertyEnableBackground:
8176 // accumulate | new [x] [y] [width] [height] | inherit
8177 if (id == CSSValueAccumulate) // TODO : new
8178 validPrimitive = true;
8181 case CSSPropertyMarkerStart:
8182 case CSSPropertyMarkerMid:
8183 case CSSPropertyMarkerEnd:
8184 case CSSPropertyMask:
8185 if (id == CSSValueNone) {
8186 validPrimitive = true;
8187 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
8188 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
8190 m_valueList->next();
8194 case CSSPropertyClipRule: // nonzero | evenodd | inherit
8195 case CSSPropertyFillRule:
8196 if (id == CSSValueNonzero || id == CSSValueEvenodd)
8197 validPrimitive = true;
8200 case CSSPropertyStrokeMiterlimit: // <miterlimit> | inherit
8201 validPrimitive = validUnit(value, FNumber | FNonNeg, SVGAttributeMode);
8204 case CSSPropertyStrokeLinejoin: // miter | round | bevel | inherit
8205 if (id == CSSValueMiter || id == CSSValueRound || id == CSSValueBevel)
8206 validPrimitive = true;
8209 case CSSPropertyStrokeLinecap: // butt | round | square | inherit
8210 if (id == CSSValueButt || id == CSSValueRound || id == CSSValueSquare)
8211 validPrimitive = true;
8214 case CSSPropertyStrokeOpacity: // <opacity-value> | inherit
8215 case CSSPropertyFillOpacity:
8216 case CSSPropertyStopOpacity:
8217 case CSSPropertyFloodOpacity:
8218 validPrimitive = (!id && validUnit(value, FNumber | FPercent, SVGAttributeMode));
8221 case CSSPropertyShapeRendering:
8222 // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
8223 if (id == CSSValueAuto || id == CSSValueOptimizespeed
8224 || id == CSSValueCrispedges || id == CSSValueGeometricprecision)
8225 validPrimitive = true;
8228 case CSSPropertyImageRendering: // auto | optimizeSpeed |
8229 case CSSPropertyColorRendering: // optimizeQuality | inherit
8230 if (id == CSSValueAuto || id == CSSValueOptimizespeed
8231 || id == CSSValueOptimizequality)
8232 validPrimitive = true;
8235 case CSSPropertyBufferedRendering: // auto | dynamic | static
8236 if (id == CSSValueAuto || id == CSSValueDynamic || id == CSSValueStatic)
8237 validPrimitive = true;
8240 case CSSPropertyColorInterpolation: // auto | sRGB | linearRGB | inherit
8241 case CSSPropertyColorInterpolationFilters:
8242 if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb)
8243 validPrimitive = true;
8246 /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
8247 * correctly and allows optimization in applyRule(..)
8250 case CSSPropertyTextAnchor: // start | middle | end | inherit
8251 if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd)
8252 validPrimitive = true;
8255 case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit
8256 if (id == CSSValueAuto) {
8257 validPrimitive = true;
8260 /* fallthrough intentional */
8261 case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
8262 if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) {
8263 parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG);
8266 m_valueList->next();
8270 case CSSPropertyFill: // <paint> | inherit
8271 case CSSPropertyStroke: // <paint> | inherit
8273 if (id == CSSValueNone) {
8274 parsedValue = SVGPaint::createNone();
8275 } else if (id == CSSValueCurrentcolor) {
8276 parsedValue = SVGPaint::createCurrentColor();
8277 } else if (isSystemColor(id)) {
8278 parsedValue = SVGPaint::createColor(RenderTheme::theme().systemColor(id));
8279 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
8280 RGBA32 c = Color::transparent;
8281 if (m_valueList->next()) {
8282 if (parseColorFromValue(m_valueList->current(), c))
8283 parsedValue = SVGPaint::createURIAndColor(value->string, c);
8284 else if (m_valueList->current()->id == CSSValueNone)
8285 parsedValue = SVGPaint::createURIAndNone(value->string);
8286 else if (m_valueList->current()->id == CSSValueCurrentcolor)
8287 parsedValue = SVGPaint::createURIAndCurrentColor(value->string);
8290 parsedValue = SVGPaint::createURI(value->string);
8292 parsedValue = parseSVGPaint();
8296 m_valueList->next();
8300 case CSSPropertyStopColor: // TODO : icccolor
8301 case CSSPropertyFloodColor:
8302 case CSSPropertyLightingColor:
8303 if (isSystemColor(id)) {
8304 parsedValue = cssValuePool().createColorValue(RenderTheme::theme().systemColor(id).rgb());
8305 } else if ((id >= CSSValueAqua && id <= CSSValueTransparent)
8306 || (id >= CSSValueAliceblue && id <= CSSValueYellowgreen) || id == CSSValueGrey) {
8307 StyleColor styleColor = SVGPaint::colorFromRGBColorString(value->string);
8308 ASSERT(!styleColor.isCurrentColor());
8309 parsedValue = cssValuePool().createColorValue(styleColor.color().rgb());
8310 } else if (id == CSSValueCurrentcolor) {
8311 parsedValue = cssValuePool().createIdentifierValue(id);
8312 } else { // TODO : svgcolor (iccColor)
8313 parsedValue = parseColor();
8317 m_valueList->next();
8321 case CSSPropertyPaintOrder:
8322 if (!RuntimeEnabledFeatures::svgPaintOrderEnabled())
8325 if (m_valueList->size() == 1 && id == CSSValueNormal)
8326 validPrimitive = true;
8327 else if ((parsedValue = parsePaintOrder()))
8328 m_valueList->next();
8331 case CSSPropertyVectorEffect: // none | non-scaling-stroke | inherit
8332 if (id == CSSValueNone || id == CSSValueNonScalingStroke)
8333 validPrimitive = true;
8336 case CSSPropertyWritingMode:
8337 // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
8338 if (id == CSSValueLrTb || id == CSSValueRlTb || id == CSSValueTbRl || id == CSSValueLr || id == CSSValueRl || id == CSSValueTb)
8339 validPrimitive = true;
8342 case CSSPropertyStrokeWidth: // <length> | inherit
8343 case CSSPropertyStrokeDashoffset:
8344 validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
8346 case CSSPropertyStrokeDasharray: // none | <dasharray> | inherit
8347 if (id == CSSValueNone)
8348 validPrimitive = true;
8350 parsedValue = parseSVGStrokeDasharray();
8354 case CSSPropertyClipPath: // <uri> | none | inherit
8355 case CSSPropertyFilter:
8356 if (id == CSSValueNone) {
8357 validPrimitive = true;
8358 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
8359 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
8361 m_valueList->next();
8364 case CSSPropertyMaskType: // luminance | alpha | inherit
8365 if (id == CSSValueLuminance || id == CSSValueAlpha)
8366 validPrimitive = true;
8369 /* shorthand properties */
8370 case CSSPropertyMarker: {
8371 ShorthandScope scope(this, propId);
8372 CSSPropertyParser::ImplicitScope implicitScope(this, PropertyImplicit);
8373 if (!parseValue(CSSPropertyMarkerStart, important))
8375 if (m_valueList->current()) {
8376 rollbackLastProperties(1);
8379 CSSValue* value = m_parsedProperties.last().value();
8380 addProperty(CSSPropertyMarkerMid, value, important);
8381 addProperty(CSSPropertyMarkerEnd, value, important);
8385 // If you crash here, it's because you added a css property and are not handling it
8386 // in either this switch statement or the one in CSSPropertyParser::parseValue
8387 ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
8391 if (validPrimitive) {
8393 parsedValue = CSSPrimitiveValue::createIdentifier(id);
8394 else if (value->unit == CSSPrimitiveValue::CSS_STRING)
8395 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
8396 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
8397 parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
8398 else if (value->unit >= CSSParserValue::Q_EMS)
8399 parsedValue = CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
8400 if (isCalculation(value)) {
8401 // FIXME calc() http://webkit.org/b/16662 : actually create a CSSPrimitiveValue here, ie
8402 // parsedValue = CSSPrimitiveValue::create(m_parsedCalculation.release());
8403 m_parsedCalculation.release();
8404 parsedValue = nullptr;
8406 m_valueList->next();
8408 if (!parsedValue || (m_valueList->current() && !inShorthand()))
8411 addProperty(propId, parsedValue.release(), important);
8415 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGStrokeDasharray()
8417 RefPtrWillBeRawPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
8418 CSSParserValue* value = m_valueList->current();
8419 bool validPrimitive = true;
8421 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttributeMode);
8422 if (!validPrimitive)
8425 ret->append(CSSPrimitiveValue::createIdentifier(value->id));
8426 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
8427 ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
8428 value = m_valueList->next();
8429 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
8430 value = m_valueList->next();
8432 if (!validPrimitive)
8434 return ret.release();
8437 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGPaint()
8439 RGBA32 c = Color::transparent;
8440 if (!parseColorFromValue(m_valueList->current(), c))
8441 return SVGPaint::createUnknown();
8442 return SVGPaint::createColor(Color(c));
8445 // normal | [ fill || stroke || markers ]
8446 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parsePaintOrder() const
8448 if (m_valueList->size() > 3)
8451 CSSParserValue* value = m_valueList->current();
8455 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
8457 // The default paint-order is: Fill, Stroke, Markers.
8458 bool seenFill = false, seenStroke = false, seenMarkers = false;
8461 switch (value->id) {
8462 case CSSValueNormal:
8463 // normal inside [fill || stroke || markers] not valid
8471 case CSSValueStroke:
8477 case CSSValueMarkers:
8487 parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id));
8488 } while ((value = m_valueList->next()));
8490 // fill out the rest of the paint order
8492 parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueFill));
8494 parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueStroke));
8496 parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueMarkers));
8498 return parsedValues.release();
8501 } // namespace WebCore