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"
30 // FIXME: Way too many!
31 #include "core/CSSValueKeywords.h"
32 #include "core/StylePropertyShorthand.h"
33 #include "core/css/CSSArrayFunctionValue.h"
34 #include "core/css/CSSAspectRatioValue.h"
35 #include "core/css/CSSBasicShapes.h"
36 #include "core/css/CSSBorderImage.h"
37 #include "core/css/CSSCanvasValue.h"
38 #include "core/css/CSSCrossfadeValue.h"
39 #include "core/css/CSSCursorImageValue.h"
40 #include "core/css/CSSFontFaceSrcValue.h"
41 #include "core/css/CSSFontFeatureValue.h"
42 #include "core/css/CSSFunctionValue.h"
43 #include "core/css/CSSGradientValue.h"
44 #include "core/css/CSSGridLineNamesValue.h"
45 #include "core/css/CSSGridTemplateAreasValue.h"
46 #include "core/css/CSSImageSetValue.h"
47 #include "core/css/CSSImageValue.h"
48 #include "core/css/CSSInheritedValue.h"
49 #include "core/css/CSSInitialValue.h"
50 #include "core/css/CSSKeyframeRule.h"
51 #include "core/css/CSSKeyframesRule.h"
52 #include "core/css/CSSLineBoxContainValue.h"
53 #include "core/css/CSSParserValues.h"
54 #include "core/css/CSSPrimitiveValue.h"
55 #include "core/css/CSSPropertySourceData.h"
56 #include "core/css/CSSReflectValue.h"
57 #include "core/css/CSSSVGDocumentValue.h"
58 #include "core/css/CSSSelector.h"
59 #include "core/css/CSSShadowValue.h"
60 #include "core/css/CSSTimingFunctionValue.h"
61 #include "core/css/CSSTransformValue.h"
62 #include "core/css/CSSUnicodeRangeValue.h"
63 #include "core/css/CSSValueList.h"
64 #include "core/css/CSSValuePool.h"
65 #include "core/css/Counter.h"
66 #include "core/css/HashTools.h"
67 #include "core/css/Pair.h"
68 #include "core/css/Rect.h"
69 #include "core/css/RuntimeCSSEnabled.h"
70 #include "core/css/parser/CSSParserIdioms.h"
71 #include "core/html/parser/HTMLParserIdioms.h"
72 #include "core/inspector/InspectorInstrumentation.h"
73 #include "core/rendering/RenderTheme.h"
74 #include "core/svg/SVGPaint.h"
75 #include "platform/FloatConversion.h"
76 #include "platform/RuntimeEnabledFeatures.h"
77 #include "wtf/BitArray.h"
78 #include "wtf/HexNumber.h"
79 #include "wtf/text/StringBuffer.h"
80 #include "wtf/text/StringBuilder.h"
81 #include "wtf/text/StringImpl.h"
82 #include "wtf/text/TextEncoding.h"
87 static const double MAX_SCALE = 1000000;
88 static const unsigned minRepetitions = 10000;
91 static bool equal(const CSSParserString& a, const char (&b)[N])
93 unsigned length = N - 1; // Ignore the trailing null character
94 if (a.length() != length)
97 return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar*>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length);
100 template <unsigned N>
101 static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
103 unsigned length = N - 1; // Ignore the trailing null character
104 if (a.length() != length)
107 return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length);
110 template <unsigned N>
111 static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N])
113 ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrimitiveValue::CSS_STRING);
114 return equalIgnoringCase(value->string, b);
117 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> first, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> second, Pair::IdenticalValuesPolicy identicalValuesPolicy = Pair::DropIdenticalValues)
119 return cssValuePool().createValue(Pair::create(first, second, identicalValuesPolicy));
122 CSSPropertyParser::CSSPropertyParser(OwnPtr<CSSParserValueList>& valueList,
123 const CSSParserContext& context, bool inViewport, bool savedImportant,
124 WillBeHeapVector<CSSProperty, 256>& parsedProperties,
125 CSSRuleSourceData::Type ruleType)
126 : m_valueList(valueList)
128 , m_inViewport(inViewport)
129 , m_important(savedImportant) // See comment in header, should be removed.
130 , m_parsedProperties(parsedProperties)
131 , m_ruleType(ruleType)
132 , m_inParseShorthand(0)
133 , m_currentShorthand(CSSPropertyInvalid)
134 , m_implicitShorthand(false)
138 CSSPropertyParser::~CSSPropertyParser()
142 void CSSPropertyParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important, bool implicit)
144 RefPtrWillBeRawPtr<CSSValue> val = value.get();
145 addProperty(propId, value, important, implicit);
147 CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId);
148 if (prefixingVariant == propId)
151 if (m_currentShorthand) {
152 // We can't use ShorthandScope here as we can already be inside one (e.g we are parsing CSSTransition).
153 m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
154 addProperty(prefixingVariant, val.release(), important, implicit);
155 m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
157 addProperty(prefixingVariant, val.release(), important, implicit);
161 void CSSPropertyParser::addProperty(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important, bool implicit)
163 // This property doesn't belong to a shorthand.
164 if (!m_currentShorthand) {
165 m_parsedProperties.append(CSSProperty(propId, value, important, false, CSSPropertyInvalid, m_implicitShorthand || implicit));
169 Vector<StylePropertyShorthand, 4> shorthands;
170 getMatchingShorthandsForLonghand(propId, &shorthands);
171 // The longhand does not belong to multiple shorthands.
172 if (shorthands.size() == 1)
173 m_parsedProperties.append(CSSProperty(propId, value, important, true, CSSPropertyInvalid, m_implicitShorthand || implicit));
175 m_parsedProperties.append(CSSProperty(propId, value, important, true, indexOfShorthandForLonghand(m_currentShorthand, shorthands), m_implicitShorthand || implicit));
178 void CSSPropertyParser::rollbackLastProperties(int num)
181 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
182 m_parsedProperties.shrink(m_parsedProperties.size() - num);
185 KURL CSSPropertyParser::completeURL(const String& url) const
187 return m_context.completeURL(url);
190 bool CSSPropertyParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc)
192 bool mustBeNonNegative = unitflags & FNonNeg;
194 if (!parseCalculation(value, mustBeNonNegative ? ValueRangeNonNegative : ValueRangeAll))
198 switch (m_parsedCalculation->category()) {
200 b = (unitflags & FLength);
203 b = (unitflags & FPercent);
204 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
208 b = (unitflags & FNumber);
209 if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
211 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
214 case CalcPercentLength:
215 b = (unitflags & FPercent) && (unitflags & FLength);
217 case CalcPercentNumber:
218 b = (unitflags & FPercent) && (unitflags & FNumber);
223 if (!b || releaseCalc == ReleaseParsedCalcValue)
224 m_parsedCalculation.release();
228 inline bool CSSPropertyParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
230 // Quirks mode and presentation attributes accept unit less values.
231 return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || isUnitLessLengthParsingEnabledForMode(cssParserMode));
234 bool CSSPropertyParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
236 if (isCalculation(value))
237 return validCalculationUnit(value, unitflags, releaseCalc);
240 switch (value->unit) {
241 case CSSPrimitiveValue::CSS_NUMBER:
242 b = (unitflags & FNumber);
243 if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
244 value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
245 ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
248 if (!b && (unitflags & FInteger) && value->isInt)
250 if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0)
253 case CSSPrimitiveValue::CSS_PERCENTAGE:
254 b = (unitflags & FPercent);
256 case CSSParserValue::Q_EMS:
257 case CSSPrimitiveValue::CSS_EMS:
258 case CSSPrimitiveValue::CSS_REMS:
259 case CSSPrimitiveValue::CSS_CHS:
260 case CSSPrimitiveValue::CSS_EXS:
261 case CSSPrimitiveValue::CSS_PX:
262 case CSSPrimitiveValue::CSS_CM:
263 case CSSPrimitiveValue::CSS_MM:
264 case CSSPrimitiveValue::CSS_IN:
265 case CSSPrimitiveValue::CSS_PT:
266 case CSSPrimitiveValue::CSS_PC:
267 case CSSPrimitiveValue::CSS_VW:
268 case CSSPrimitiveValue::CSS_VH:
269 case CSSPrimitiveValue::CSS_VMIN:
270 case CSSPrimitiveValue::CSS_VMAX:
271 b = (unitflags & FLength);
273 case CSSPrimitiveValue::CSS_MS:
274 case CSSPrimitiveValue::CSS_S:
275 b = (unitflags & FTime);
277 case CSSPrimitiveValue::CSS_DEG:
278 case CSSPrimitiveValue::CSS_RAD:
279 case CSSPrimitiveValue::CSS_GRAD:
280 case CSSPrimitiveValue::CSS_TURN:
281 b = (unitflags & FAngle);
283 case CSSPrimitiveValue::CSS_DPPX:
284 case CSSPrimitiveValue::CSS_DPI:
285 case CSSPrimitiveValue::CSS_DPCM:
286 b = (unitflags & FResolution);
288 case CSSPrimitiveValue::CSS_HZ:
289 case CSSPrimitiveValue::CSS_KHZ:
290 case CSSPrimitiveValue::CSS_DIMENSION:
294 if (b && unitflags & FNonNeg && value->fValue < 0)
299 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimitiveNumericValue(CSSParserValue* value)
301 if (m_parsedCalculation) {
302 ASSERT(isCalculation(value));
303 return CSSPrimitiveValue::create(m_parsedCalculation.release());
306 ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
307 || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
308 || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
309 || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
310 return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitType>(value->unit));
313 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimitiveStringValue(CSSParserValue* value)
315 ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
316 return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
319 inline PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::createCSSImageValueWithReferrer(const String& rawValue, const KURL& url)
321 RefPtrWillBeRawPtr<CSSValue> imageValue = CSSImageValue::create(rawValue, url);
322 toCSSImageValue(imageValue.get())->setReferrer(m_context.referrer());
326 static inline bool isComma(CSSParserValue* value)
328 return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
331 static inline bool isForwardSlashOperator(CSSParserValue* value)
334 return value->unit == CSSParserValue::Operator && value->iValue == '/';
337 static bool isGeneratedImageValue(CSSParserValue* val)
339 if (val->unit != CSSParserValue::Function)
342 return equalIgnoringCase(val->function->name, "-webkit-gradient(")
343 || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
344 || equalIgnoringCase(val->function->name, "linear-gradient(")
345 || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
346 || equalIgnoringCase(val->function->name, "repeating-linear-gradient(")
347 || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
348 || equalIgnoringCase(val->function->name, "radial-gradient(")
349 || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
350 || equalIgnoringCase(val->function->name, "repeating-radial-gradient(")
351 || equalIgnoringCase(val->function->name, "-webkit-canvas(")
352 || equalIgnoringCase(val->function->name, "-webkit-cross-fade(");
355 bool CSSPropertyParser::validWidthOrHeight(CSSParserValue* value)
358 if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
360 return !id && validUnit(value, FLength | FPercent | FNonNeg);
363 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value)
366 return cssValuePool().createIdentifierValue(identifier);
367 if (value->unit == CSSPrimitiveValue::CSS_STRING)
368 return createPrimitiveStringValue(value);
369 if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
370 return createPrimitiveNumericValue(value);
371 if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
372 return createPrimitiveNumericValue(value);
373 if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
374 return createPrimitiveNumericValue(value);
375 if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
376 return createPrimitiveNumericValue(value);
377 if (value->unit >= CSSParserValue::Q_EMS)
378 return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
379 if (isCalculation(value))
380 return CSSPrimitiveValue::create(m_parsedCalculation.release());
385 void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> prpValue, bool important)
387 const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
388 unsigned shorthandLength = shorthand.length();
389 if (!shorthandLength) {
390 addPropertyWithPrefixingVariant(propId, prpValue, important);
394 RefPtrWillBeRawPtr<CSSValue> value = prpValue;
395 ShorthandScope scope(this, propId);
396 const CSSPropertyID* longhands = shorthand.properties();
397 for (unsigned i = 0; i < shorthandLength; ++i)
398 addPropertyWithPrefixingVariant(longhands[i], value, important);
401 bool CSSPropertyParser::parseValue(CSSPropertyID propId, bool important)
403 if (!isInternalPropertyAndValueParsingEnabledForMode(m_context.mode()) && isInternalProperty(propId))
406 // We don't count the UA style sheet in our statistics.
407 if (m_context.useCounter())
408 m_context.useCounter()->count(m_context, propId);
413 CSSParserValue* value = m_valueList->current();
419 // Allow @viewport rules from UA stylesheets even if the feature is disabled.
420 if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode()))
423 return parseViewportProperty(propId, important);
426 // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
427 // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
428 ASSERT(!m_parsedCalculation);
430 CSSValueID id = value->id;
432 int num = inShorthand() ? 1 : m_valueList->size();
434 if (id == CSSValueInherit) {
437 addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important);
440 else if (id == CSSValueInitial) {
443 addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important);
447 if (isKeywordPropertyID(propId)) {
448 if (!isValidKeywordPropertyAndValue(propId, id, m_context))
450 if (m_valueList->next() && !inShorthand())
452 addProperty(propId, cssValuePool().createIdentifierValue(id), important);
456 bool validPrimitive = false;
457 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
460 case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
461 return parseSize(propId, important);
463 case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit
465 validPrimitive = true;
467 return parseQuotes(propId, important);
469 case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | isolate-override | plaintext | inherit
470 if (id == CSSValueNormal
471 || id == CSSValueEmbed
472 || id == CSSValueBidiOverride
473 || id == CSSValueWebkitIsolate
474 || id == CSSValueWebkitIsolateOverride
475 || id == CSSValueWebkitPlaintext)
476 validPrimitive = true;
479 case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
480 // close-quote | no-open-quote | no-close-quote ]+ | inherit
481 return parseContent(propId, important);
483 case CSSPropertyClip: // <shape> | auto | inherit
484 if (id == CSSValueAuto)
485 validPrimitive = true;
486 else if (value->unit == CSSParserValue::Function)
487 return parseClipShape(propId, important);
490 /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
491 * correctly and allows optimization in WebCore::applyRule(..)
493 case CSSPropertyOverflow: {
494 ShorthandScope scope(this, propId);
495 if (num != 1 || !parseValue(CSSPropertyOverflowY, important))
498 RefPtrWillBeRawPtr<CSSValue> overflowXValue = nullptr;
500 // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been
501 // set using the shorthand, then for now overflow-x will default to auto, but once we implement
502 // pagination controls, it should default to hidden. If the overflow-y value is anything but
503 // paged-x or paged-y, then overflow-x and overflow-y should have the same value.
504 if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
505 overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
507 overflowXValue = m_parsedProperties.last().value();
508 addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
512 case CSSPropertyTextAlign:
513 // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
514 // | start | end | <string> | inherit | -webkit-auto (converted to start)
515 if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
516 || value->unit == CSSPrimitiveValue::CSS_STRING)
517 validPrimitive = true;
520 case CSSPropertyFontWeight: { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
521 if (m_valueList->size() != 1)
523 return parseFontWeight(important);
525 case CSSPropertyBorderSpacing: {
527 ShorthandScope scope(this, CSSPropertyBorderSpacing);
528 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
530 CSSValue* value = m_parsedProperties.last().value();
531 addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
535 ShorthandScope scope(this, CSSPropertyBorderSpacing);
536 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
542 case CSSPropertyWebkitBorderHorizontalSpacing:
543 case CSSPropertyWebkitBorderVerticalSpacing:
544 validPrimitive = validUnit(value, FLength | FNonNeg);
546 case CSSPropertyOutlineColor: // <color> | invert | inherit
547 // Outline color has "invert" as additional keyword.
548 // Also, we want to allow the special focus color even in HTML Standard parsing mode.
549 if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
550 validPrimitive = true;
554 case CSSPropertyBackgroundColor: // <color> | inherit
555 case CSSPropertyBorderTopColor: // <color> | inherit
556 case CSSPropertyBorderRightColor:
557 case CSSPropertyBorderBottomColor:
558 case CSSPropertyBorderLeftColor:
559 case CSSPropertyWebkitBorderStartColor:
560 case CSSPropertyWebkitBorderEndColor:
561 case CSSPropertyWebkitBorderBeforeColor:
562 case CSSPropertyWebkitBorderAfterColor:
563 case CSSPropertyColor: // <color> | inherit
564 case CSSPropertyTextDecorationColor: // CSS3 text decoration colors
565 case CSSPropertyTextLineThroughColor:
566 case CSSPropertyTextUnderlineColor:
567 case CSSPropertyTextOverlineColor:
568 case CSSPropertyWebkitColumnRuleColor:
569 case CSSPropertyWebkitTextEmphasisColor:
570 case CSSPropertyWebkitTextFillColor:
571 case CSSPropertyWebkitTextStrokeColor:
572 if (propId == CSSPropertyTextDecorationColor
573 && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
576 if ((id >= CSSValueAqua && id <= CSSValueWebkitText) || id == CSSValueMenu) {
577 validPrimitive = isValueAllowedInMode(id, m_context.mode());
579 parsedValue = parseColor();
585 case CSSPropertyCursor: {
586 // Grammar defined by CSS3 UI and modified by CSS4 images:
587 // [ [<image> [<x> <y>]?,]*
588 // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
589 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
590 // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
591 // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | all-scroll |
592 // zoom-in | zoom-out | -webkit-grab | -webkit-grabbing | -webkit-zoom-in | -webkit-zoom-out ] ] | inherit
593 RefPtrWillBeRawPtr<CSSValueList> list = nullptr;
595 RefPtrWillBeRawPtr<CSSValue> image = nullptr;
596 if (value->unit == CSSPrimitiveValue::CSS_URI) {
597 String uri = value->string;
599 image = createCSSImageValueWithReferrer(uri, completeURL(uri));
600 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
601 image = parseImageSet(m_valueList.get());
608 value = m_valueList->next();
609 while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
610 coords.append(int(value->fValue));
611 value = m_valueList->next();
613 bool hasHotSpot = false;
614 IntPoint hotSpot(-1, -1);
615 int nrcoords = coords.size();
616 if (nrcoords > 0 && nrcoords != 2)
620 hotSpot = IntPoint(coords[0], coords[1]);
624 list = CSSValueList::createCommaSeparated();
627 list->append(CSSCursorImageValue::create(image, hasHotSpot, hotSpot));
629 if (!value || !(value->unit == CSSParserValue::Operator && value->iValue == ','))
631 value = m_valueList->next(); // comma
633 if (value && m_context.useCounter()) {
634 if (value->id == CSSValueWebkitZoomIn)
635 m_context.useCounter()->count(UseCounter::PrefixedCursorZoomIn);
636 else if (value->id == CSSValueWebkitZoomOut)
637 m_context.useCounter()->count(UseCounter::PrefixedCursorZoomOut);
642 if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
643 list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
644 else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitZoomOut) || value->id == CSSValueCopy || value->id == CSSValueNone)
645 list->append(cssValuePool().createIdentifierValue(value->id));
647 parsedValue = list.release();
651 if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
652 id = CSSValuePointer;
653 validPrimitive = true;
654 } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitZoomOut) || value->id == CSSValueCopy || value->id == CSSValueNone)
655 validPrimitive = true;
657 ASSERT_NOT_REACHED();
663 case CSSPropertyBackgroundBlendMode:
664 case CSSPropertyBackgroundAttachment:
665 case CSSPropertyBackgroundClip:
666 case CSSPropertyWebkitBackgroundClip:
667 case CSSPropertyWebkitBackgroundComposite:
668 case CSSPropertyBackgroundImage:
669 case CSSPropertyBackgroundOrigin:
670 case CSSPropertyMaskSourceType:
671 case CSSPropertyWebkitBackgroundOrigin:
672 case CSSPropertyBackgroundPosition:
673 case CSSPropertyBackgroundPositionX:
674 case CSSPropertyBackgroundPositionY:
675 case CSSPropertyBackgroundSize:
676 case CSSPropertyWebkitBackgroundSize:
677 case CSSPropertyBackgroundRepeat:
678 case CSSPropertyBackgroundRepeatX:
679 case CSSPropertyBackgroundRepeatY:
680 case CSSPropertyWebkitMaskClip:
681 case CSSPropertyWebkitMaskComposite:
682 case CSSPropertyWebkitMaskImage:
683 case CSSPropertyWebkitMaskOrigin:
684 case CSSPropertyWebkitMaskPosition:
685 case CSSPropertyWebkitMaskPositionX:
686 case CSSPropertyWebkitMaskPositionY:
687 case CSSPropertyWebkitMaskSize:
688 case CSSPropertyWebkitMaskRepeat:
689 case CSSPropertyWebkitMaskRepeatX:
690 case CSSPropertyWebkitMaskRepeatY:
692 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
693 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
694 CSSPropertyID propId1, propId2;
696 if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
697 if (propId == CSSPropertyBackgroundPosition ||
698 propId == CSSPropertyBackgroundRepeat ||
699 propId == CSSPropertyWebkitMaskPosition ||
700 propId == CSSPropertyWebkitMaskRepeat) {
701 ShorthandScope scope(this, propId);
702 addProperty(propId1, val1.release(), important);
704 addProperty(propId2, val2.release(), important);
706 addProperty(propId1, val1.release(), important);
708 addProperty(propId2, val2.release(), important);
712 m_implicitShorthand = false;
715 case CSSPropertyObjectPosition:
716 return RuntimeEnabledFeatures::objectFitPositionEnabled() && parseObjectPosition(important);
717 case CSSPropertyListStyleImage: // <uri> | none | inherit
718 case CSSPropertyBorderImageSource:
719 case CSSPropertyWebkitMaskBoxImageSource:
720 if (id == CSSValueNone) {
721 parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
723 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
724 parsedValue = createCSSImageValueWithReferrer(value->string, completeURL(value->string));
726 } else if (isGeneratedImageValue(value)) {
727 if (parseGeneratedImage(m_valueList.get(), parsedValue))
732 else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
733 parsedValue = parseImageSet(m_valueList.get());
740 case CSSPropertyWebkitTextStrokeWidth:
741 case CSSPropertyOutlineWidth: // <border-width> | inherit
742 case CSSPropertyBorderTopWidth: //// <border-width> | inherit
743 case CSSPropertyBorderRightWidth: // Which is defined as
744 case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
745 case CSSPropertyBorderLeftWidth:
746 case CSSPropertyWebkitBorderStartWidth:
747 case CSSPropertyWebkitBorderEndWidth:
748 case CSSPropertyWebkitBorderBeforeWidth:
749 case CSSPropertyWebkitBorderAfterWidth:
750 case CSSPropertyWebkitColumnRuleWidth:
751 if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
752 validPrimitive = true;
754 validPrimitive = validUnit(value, FLength | FNonNeg);
757 case CSSPropertyLetterSpacing: // normal | <length> | inherit
758 case CSSPropertyWordSpacing: // normal | <length> | inherit
759 if (id == CSSValueNormal)
760 validPrimitive = true;
762 validPrimitive = validUnit(value, FLength);
765 case CSSPropertyTextIndent:
766 parsedValue = parseTextIndent();
769 case CSSPropertyPaddingTop: //// <padding-width> | inherit
770 case CSSPropertyPaddingRight: // Which is defined as
771 case CSSPropertyPaddingBottom: // <length> | <percentage>
772 case CSSPropertyPaddingLeft: ////
773 case CSSPropertyWebkitPaddingStart:
774 case CSSPropertyWebkitPaddingEnd:
775 case CSSPropertyWebkitPaddingBefore:
776 case CSSPropertyWebkitPaddingAfter:
777 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
780 case CSSPropertyMaxWidth:
781 case CSSPropertyWebkitMaxLogicalWidth:
782 case CSSPropertyMaxHeight:
783 case CSSPropertyWebkitMaxLogicalHeight:
784 validPrimitive = (id == CSSValueNone || validWidthOrHeight(value));
787 case CSSPropertyMinWidth:
788 case CSSPropertyWebkitMinLogicalWidth:
789 case CSSPropertyMinHeight:
790 case CSSPropertyWebkitMinLogicalHeight:
791 validPrimitive = validWidthOrHeight(value);
794 case CSSPropertyWidth:
795 case CSSPropertyWebkitLogicalWidth:
796 case CSSPropertyHeight:
797 case CSSPropertyWebkitLogicalHeight:
798 validPrimitive = (id == CSSValueAuto || validWidthOrHeight(value));
801 case CSSPropertyFontSize:
802 return parseFontSize(important);
804 case CSSPropertyFontVariant: // normal | small-caps | inherit
805 return parseFontVariant(important);
807 case CSSPropertyVerticalAlign:
808 // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
809 // <percentage> | <length> | inherit
811 if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
812 validPrimitive = true;
814 validPrimitive = (!id && validUnit(value, FLength | FPercent));
817 case CSSPropertyBottom: // <length> | <percentage> | auto | inherit
818 case CSSPropertyLeft: // <length> | <percentage> | auto | inherit
819 case CSSPropertyRight: // <length> | <percentage> | auto | inherit
820 case CSSPropertyTop: // <length> | <percentage> | auto | inherit
821 case CSSPropertyMarginTop: //// <margin-width> | inherit
822 case CSSPropertyMarginRight: // Which is defined as
823 case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit
824 case CSSPropertyMarginLeft: ////
825 case CSSPropertyWebkitMarginStart:
826 case CSSPropertyWebkitMarginEnd:
827 case CSSPropertyWebkitMarginBefore:
828 case CSSPropertyWebkitMarginAfter:
829 if (id == CSSValueAuto)
830 validPrimitive = true;
832 validPrimitive = (!id && validUnit(value, FLength | FPercent));
835 case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
836 case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
837 if (id == CSSValueAuto)
838 validPrimitive = true;
840 validPrimitive = (!id && validUnit(value, FPositiveInteger, HTMLQuirksMode));
843 case CSSPropertyZIndex: // auto | <integer> | inherit
844 if (id == CSSValueAuto)
845 validPrimitive = true;
847 validPrimitive = (!id && validUnit(value, FInteger, HTMLQuirksMode));
850 case CSSPropertyLineHeight:
851 return parseLineHeight(important);
852 case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
853 if (id != CSSValueNone)
854 return parseCounter(propId, 1, important);
855 validPrimitive = true;
857 case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit
858 if (id != CSSValueNone)
859 return parseCounter(propId, 0, important);
860 validPrimitive = true;
862 case CSSPropertyFontFamily:
863 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
865 parsedValue = parseFontFamily();
869 case CSSPropertyTextDecoration:
870 // Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration
871 // is disabled to match CSS 2.1 rules for parsing 'text-decoration'.
872 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) {
873 // [ <text-decoration-line> || <text-decoration-style> || <text-decoration-color> ] | inherit
874 return parseShorthand(CSSPropertyTextDecoration, textDecorationShorthand(), important);
876 case CSSPropertyWebkitTextDecorationsInEffect:
877 case CSSPropertyTextDecorationLine:
878 // none | [ underline || overline || line-through || blink ] | inherit
879 return parseTextDecoration(propId, important);
881 case CSSPropertyTextDecorationStyle:
882 // solid | double | dotted | dashed | wavy
883 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()
884 && (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDotted || id == CSSValueDashed || id == CSSValueWavy))
885 validPrimitive = true;
888 case CSSPropertyTextUnderlinePosition:
889 // auto | under | inherit
890 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled())
891 return parseTextUnderlinePosition(important);
894 case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit
895 if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
896 validPrimitive = true;
898 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode));
901 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.
902 return parseFontFaceSrc();
904 case CSSPropertyUnicodeRange:
905 return parseFontFaceUnicodeRange();
907 /* CSS3 properties */
909 case CSSPropertyBorderImage:
910 case CSSPropertyWebkitMaskBoxImage:
911 return parseBorderImageShorthand(propId, important);
912 case CSSPropertyWebkitBorderImage: {
913 if (RefPtrWillBeRawPtr<CSSValue> result = parseBorderImage(propId)) {
914 addProperty(propId, result, important);
920 case CSSPropertyBorderImageOutset:
921 case CSSPropertyWebkitMaskBoxImageOutset: {
922 RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
923 if (parseBorderImageOutset(result)) {
924 addProperty(propId, result, important);
929 case CSSPropertyBorderImageRepeat:
930 case CSSPropertyWebkitMaskBoxImageRepeat: {
931 RefPtrWillBeRawPtr<CSSValue> result = nullptr;
932 if (parseBorderImageRepeat(result)) {
933 addProperty(propId, result, important);
938 case CSSPropertyBorderImageSlice:
939 case CSSPropertyWebkitMaskBoxImageSlice: {
940 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> result = nullptr;
941 if (parseBorderImageSlice(propId, result)) {
942 addProperty(propId, result, important);
947 case CSSPropertyBorderImageWidth:
948 case CSSPropertyWebkitMaskBoxImageWidth: {
949 RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
950 if (parseBorderImageWidth(result)) {
951 addProperty(propId, result, important);
956 case CSSPropertyBorderTopRightRadius:
957 case CSSPropertyBorderTopLeftRadius:
958 case CSSPropertyBorderBottomLeftRadius:
959 case CSSPropertyBorderBottomRightRadius: {
960 if (num != 1 && num != 2)
962 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
965 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
966 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr;
968 value = m_valueList->next();
969 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
972 parsedValue2 = createPrimitiveNumericValue(value);
974 parsedValue2 = parsedValue1;
976 addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important);
979 case CSSPropertyTabSize:
980 validPrimitive = validUnit(value, FInteger | FNonNeg);
982 case CSSPropertyWebkitAspectRatio:
983 return parseAspectRatio(important);
984 case CSSPropertyBorderRadius:
985 case CSSPropertyWebkitBorderRadius:
986 return parseBorderRadius(propId, important);
987 case CSSPropertyOutlineOffset:
988 validPrimitive = validUnit(value, FLength);
990 case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
991 case CSSPropertyBoxShadow:
992 case CSSPropertyWebkitBoxShadow:
993 if (id == CSSValueNone)
994 validPrimitive = true;
996 RefPtrWillBeRawPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
997 if (shadowValueList) {
998 addProperty(propId, shadowValueList.release(), important);
1005 case CSSPropertyWebkitBoxReflect:
1006 if (id == CSSValueNone)
1007 validPrimitive = true;
1009 return parseReflect(propId, important);
1011 case CSSPropertyOpacity:
1012 validPrimitive = validUnit(value, FNumber);
1014 case CSSPropertyWebkitBoxFlex:
1015 validPrimitive = validUnit(value, FNumber);
1017 case CSSPropertyWebkitBoxFlexGroup:
1018 validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode);
1020 case CSSPropertyWebkitBoxOrdinalGroup:
1021 validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode) && value->fValue;
1023 case CSSPropertyWebkitFilter:
1024 if (id == CSSValueNone)
1025 validPrimitive = true;
1027 RefPtrWillBeRawPtr<CSSValue> val = parseFilter();
1029 addProperty(propId, val, important);
1035 case CSSPropertyFlex: {
1036 ShorthandScope scope(this, propId);
1037 if (id == CSSValueNone) {
1038 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
1039 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
1040 addProperty(CSSPropertyFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
1043 return parseFlex(m_valueList.get(), important);
1045 case CSSPropertyFlexBasis:
1046 // FIXME: Support intrinsic dimensions too.
1047 if (id == CSSValueAuto)
1048 validPrimitive = true;
1050 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
1052 case CSSPropertyFlexGrow:
1053 case CSSPropertyFlexShrink:
1054 validPrimitive = validUnit(value, FNumber | FNonNeg);
1056 case CSSPropertyOrder:
1057 validPrimitive = validUnit(value, FInteger, HTMLStandardMode);
1059 case CSSPropertyInternalMarqueeIncrement:
1060 if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
1061 validPrimitive = true;
1063 validPrimitive = validUnit(value, FLength | FPercent);
1065 case CSSPropertyInternalMarqueeRepetition:
1066 if (id == CSSValueInfinite)
1067 validPrimitive = true;
1069 validPrimitive = validUnit(value, FInteger | FNonNeg);
1071 case CSSPropertyInternalMarqueeSpeed:
1072 if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
1073 validPrimitive = true;
1075 validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
1077 case CSSPropertyTransform:
1078 case CSSPropertyWebkitTransform:
1079 if (id == CSSValueNone)
1080 validPrimitive = true;
1082 RefPtrWillBeRawPtr<CSSValue> transformValue = parseTransform(propId);
1083 if (transformValue) {
1084 addProperty(propId, transformValue.release(), important);
1090 case CSSPropertyTransformOrigin: {
1091 RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin();
1094 // These values are added to match gecko serialization.
1095 if (list->length() == 1)
1096 list->append(cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
1097 if (list->length() == 2)
1098 list->append(cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX));
1099 addProperty(propId, list.release(), important);
1102 case CSSPropertyWebkitTransformOrigin:
1103 case CSSPropertyWebkitTransformOriginX:
1104 case CSSPropertyWebkitTransformOriginY:
1105 case CSSPropertyWebkitTransformOriginZ: {
1106 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
1107 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
1108 RefPtrWillBeRawPtr<CSSValue> val3 = nullptr;
1109 CSSPropertyID propId1, propId2, propId3;
1110 if (parseWebkitTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
1111 addProperty(propId1, val1.release(), important);
1113 addProperty(propId2, val2.release(), important);
1115 addProperty(propId3, val3.release(), important);
1120 case CSSPropertyPerspective:
1121 if (id == CSSValueNone) {
1122 validPrimitive = true;
1123 } else if (validUnit(value, FLength | FNonNeg)) {
1124 addProperty(propId, createPrimitiveNumericValue(value), important);
1128 case CSSPropertyWebkitPerspective:
1129 if (id == CSSValueNone) {
1130 validPrimitive = true;
1131 } else if (validUnit(value, FNumber | FLength | FNonNeg)) {
1132 // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
1133 addProperty(propId, createPrimitiveNumericValue(value), important);
1137 case CSSPropertyPerspectiveOrigin: {
1138 RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin();
1139 if (!list || list->length() == 3)
1141 // This values are added to match gecko serialization.
1142 if (list->length() == 1)
1143 list->append(cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
1144 addProperty(propId, list.release(), important);
1147 case CSSPropertyWebkitPerspectiveOrigin:
1148 case CSSPropertyWebkitPerspectiveOriginX:
1149 case CSSPropertyWebkitPerspectiveOriginY: {
1150 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
1151 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
1152 CSSPropertyID propId1, propId2;
1153 if (parseWebkitPerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
1154 addProperty(propId1, val1.release(), important);
1156 addProperty(propId2, val2.release(), important);
1161 case CSSPropertyAnimationDelay:
1162 case CSSPropertyAnimationDirection:
1163 case CSSPropertyAnimationDuration:
1164 case CSSPropertyAnimationFillMode:
1165 case CSSPropertyAnimationName:
1166 case CSSPropertyAnimationPlayState:
1167 case CSSPropertyAnimationIterationCount:
1168 case CSSPropertyAnimationTimingFunction:
1169 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
1171 case CSSPropertyWebkitAnimationDelay:
1172 case CSSPropertyWebkitAnimationDirection:
1173 case CSSPropertyWebkitAnimationDuration:
1174 case CSSPropertyWebkitAnimationFillMode:
1175 case CSSPropertyWebkitAnimationName:
1176 case CSSPropertyWebkitAnimationPlayState:
1177 case CSSPropertyWebkitAnimationIterationCount:
1178 case CSSPropertyWebkitAnimationTimingFunction:
1179 case CSSPropertyTransitionDelay:
1180 case CSSPropertyTransitionDuration:
1181 case CSSPropertyTransitionTimingFunction:
1182 case CSSPropertyTransitionProperty:
1183 case CSSPropertyWebkitTransitionDelay:
1184 case CSSPropertyWebkitTransitionDuration:
1185 case CSSPropertyWebkitTransitionTimingFunction:
1186 case CSSPropertyWebkitTransitionProperty: {
1187 if (RefPtrWillBeRawPtr<CSSValueList> val = parseAnimationPropertyList(propId)) {
1188 addPropertyWithPrefixingVariant(propId, val.release(), important);
1194 case CSSPropertyJustifySelf:
1195 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1198 return parseItemPositionOverflowPosition(propId, important);
1199 case CSSPropertyGridAutoColumns:
1200 case CSSPropertyGridAutoRows:
1201 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1203 parsedValue = parseGridTrackSize(*m_valueList);
1206 case CSSPropertyGridTemplateColumns:
1207 case CSSPropertyGridTemplateRows:
1208 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1210 parsedValue = parseGridTrackList(important);
1213 case CSSPropertyGridColumnEnd:
1214 case CSSPropertyGridColumnStart:
1215 case CSSPropertyGridRowEnd:
1216 case CSSPropertyGridRowStart:
1217 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1219 parsedValue = parseGridPosition();
1222 case CSSPropertyGridColumn:
1223 case CSSPropertyGridRow:
1224 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1226 return parseGridItemPositionShorthand(propId, important);
1228 case CSSPropertyGridArea:
1229 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1231 return parseGridAreaShorthand(important);
1233 case CSSPropertyGridTemplateAreas:
1234 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1236 parsedValue = parseGridTemplateAreas();
1239 case CSSPropertyGridTemplate:
1240 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1242 return parseGridTemplateShorthand(important);
1244 case CSSPropertyGrid:
1245 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1247 return parseGridShorthand(important);
1249 case CSSPropertyWebkitMarginCollapse: {
1251 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
1252 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important))
1254 CSSValue* value = m_parsedProperties.last().value();
1255 addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
1258 else if (num == 2) {
1259 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
1260 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important) || !parseValue(webkitMarginCollapseShorthand().properties()[1], important))
1266 case CSSPropertyTextLineThroughWidth:
1267 case CSSPropertyTextOverlineWidth:
1268 case CSSPropertyTextUnderlineWidth:
1269 if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
1270 id == CSSValueMedium || id == CSSValueThick)
1271 validPrimitive = true;
1273 validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent);
1275 case CSSPropertyWebkitColumnCount:
1276 parsedValue = parseColumnCount();
1278 case CSSPropertyWebkitColumnGap: // normal | <length>
1279 if (id == CSSValueNormal)
1280 validPrimitive = true;
1282 validPrimitive = validUnit(value, FLength | FNonNeg);
1284 case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property)
1285 if (id == CSSValueAll || id == CSSValueNone)
1286 validPrimitive = true;
1288 validPrimitive = validUnit(value, FNumber | FNonNeg) && value->fValue == 1;
1290 case CSSPropertyWebkitColumnWidth: // auto | <length>
1291 parsedValue = parseColumnWidth();
1293 case CSSPropertyWillChange:
1294 if (!RuntimeEnabledFeatures::cssWillChangeEnabled())
1296 return parseWillChange(important);
1297 // End of CSS3 properties
1299 // Apple specific properties. These will never be standardized and are purely to
1300 // support custom WebKit-based Apple applications.
1301 case CSSPropertyWebkitLineClamp:
1302 // When specifying number of lines, don't allow 0 as a valid value
1303 // When specifying either type of unit, require non-negative integers
1304 validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, HTMLQuirksMode));
1307 case CSSPropertyWebkitFontSizeDelta: // <length>
1308 validPrimitive = validUnit(value, FLength);
1311 case CSSPropertyWebkitHighlight:
1312 if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
1313 validPrimitive = true;
1316 case CSSPropertyWebkitHyphenateCharacter:
1317 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
1318 validPrimitive = true;
1321 case CSSPropertyWebkitLocale:
1322 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
1323 validPrimitive = true;
1326 // End Apple-specific properties
1328 case CSSPropertyWebkitAppRegion:
1329 if (id >= CSSValueDrag && id <= CSSValueNoDrag)
1330 validPrimitive = true;
1333 case CSSPropertyWebkitTapHighlightColor:
1334 if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu
1335 || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
1336 validPrimitive = true;
1338 parsedValue = parseColor();
1340 m_valueList->next();
1344 /* shorthand properties */
1345 case CSSPropertyBackground: {
1346 // Position must come before color in this array because a plain old "0" is a legal color
1347 // in quirks mode but it's usually the X coordinate of a position.
1348 const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
1349 CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
1350 CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
1351 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
1353 case CSSPropertyWebkitMask: {
1354 const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
1355 CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize };
1356 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
1358 case CSSPropertyBorder:
1359 // [ 'border-width' || 'border-style' || <color> ] | inherit
1361 if (parseShorthand(propId, parsingShorthandForProperty(CSSPropertyBorder), important)) {
1362 // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as
1363 // though a value of none was specified for the image.
1364 addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
1369 case CSSPropertyBorderTop:
1370 // [ 'border-top-width' || 'border-style' || <color> ] | inherit
1371 return parseShorthand(propId, borderTopShorthand(), important);
1372 case CSSPropertyBorderRight:
1373 // [ 'border-right-width' || 'border-style' || <color> ] | inherit
1374 return parseShorthand(propId, borderRightShorthand(), important);
1375 case CSSPropertyBorderBottom:
1376 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
1377 return parseShorthand(propId, borderBottomShorthand(), important);
1378 case CSSPropertyBorderLeft:
1379 // [ 'border-left-width' || 'border-style' || <color> ] | inherit
1380 return parseShorthand(propId, borderLeftShorthand(), important);
1381 case CSSPropertyWebkitBorderStart:
1382 return parseShorthand(propId, webkitBorderStartShorthand(), important);
1383 case CSSPropertyWebkitBorderEnd:
1384 return parseShorthand(propId, webkitBorderEndShorthand(), important);
1385 case CSSPropertyWebkitBorderBefore:
1386 return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
1387 case CSSPropertyWebkitBorderAfter:
1388 return parseShorthand(propId, webkitBorderAfterShorthand(), important);
1389 case CSSPropertyOutline:
1390 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
1391 return parseShorthand(propId, outlineShorthand(), important);
1392 case CSSPropertyBorderColor:
1393 // <color>{1,4} | inherit
1394 return parse4Values(propId, borderColorShorthand().properties(), important);
1395 case CSSPropertyBorderWidth:
1396 // <border-width>{1,4} | inherit
1397 return parse4Values(propId, borderWidthShorthand().properties(), important);
1398 case CSSPropertyBorderStyle:
1399 // <border-style>{1,4} | inherit
1400 return parse4Values(propId, borderStyleShorthand().properties(), important);
1401 case CSSPropertyMargin:
1402 // <margin-width>{1,4} | inherit
1403 return parse4Values(propId, marginShorthand().properties(), important);
1404 case CSSPropertyPadding:
1405 // <padding-width>{1,4} | inherit
1406 return parse4Values(propId, paddingShorthand().properties(), important);
1407 case CSSPropertyFlexFlow:
1408 return parseShorthand(propId, flexFlowShorthand(), important);
1409 case CSSPropertyFont:
1410 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
1411 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
1412 if (id >= CSSValueCaption && id <= CSSValueStatusBar)
1413 validPrimitive = true;
1415 return parseFont(important);
1417 case CSSPropertyListStyle:
1418 return parseShorthand(propId, listStyleShorthand(), important);
1419 case CSSPropertyWebkitColumns:
1420 return parseColumnsShorthand(important);
1421 case CSSPropertyWebkitColumnRule:
1422 return parseShorthand(propId, webkitColumnRuleShorthand(), important);
1423 case CSSPropertyWebkitTextStroke:
1424 return parseShorthand(propId, webkitTextStrokeShorthand(), important);
1425 case CSSPropertyAnimation:
1426 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
1428 case CSSPropertyWebkitAnimation:
1429 return parseAnimationShorthand(propId, important);
1430 case CSSPropertyTransition:
1431 case CSSPropertyWebkitTransition:
1432 return parseTransitionShorthand(propId, important);
1433 case CSSPropertyInvalid:
1435 case CSSPropertyPage:
1436 return parsePage(propId, important);
1437 case CSSPropertyFontStretch:
1439 // CSS Text Layout Module Level 3: Vertical writing support
1440 case CSSPropertyWebkitTextEmphasis:
1441 return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
1443 case CSSPropertyWebkitTextEmphasisStyle:
1444 return parseTextEmphasisStyle(important);
1446 case CSSPropertyWebkitTextOrientation:
1447 // FIXME: For now just support sideways, sideways-right, upright and vertical-right.
1448 if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSValueVerticalRight || id == CSSValueUpright)
1449 validPrimitive = true;
1452 case CSSPropertyWebkitLineBoxContain:
1453 if (id == CSSValueNone)
1454 validPrimitive = true;
1456 return parseLineBoxContain(important);
1458 case CSSPropertyWebkitFontFeatureSettings:
1459 if (id == CSSValueNormal)
1460 validPrimitive = true;
1462 return parseFontFeatureSettings(important);
1465 case CSSPropertyFontVariantLigatures:
1466 if (id == CSSValueNormal)
1467 validPrimitive = true;
1469 return parseFontVariantLigatures(important);
1471 case CSSPropertyWebkitClipPath:
1472 if (id == CSSValueNone) {
1473 validPrimitive = true;
1474 } else if (value->unit == CSSParserValue::Function) {
1475 parsedValue = parseBasicShape();
1476 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
1477 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
1478 addProperty(propId, parsedValue.release(), important);
1482 case CSSPropertyShapeOutside:
1483 parsedValue = parseShapeProperty(propId);
1485 case CSSPropertyShapeMargin:
1486 validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FLength | FPercent | FNonNeg));
1488 case CSSPropertyShapeImageThreshold:
1489 validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FNumber));
1492 case CSSPropertyTouchAction:
1493 // auto | none | [pan-x || pan-y] | manipulation
1494 return parseTouchAction(important);
1496 case CSSPropertyAlignSelf:
1497 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1498 return parseItemPositionOverflowPosition(propId, important);
1500 case CSSPropertyAlignItems:
1501 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1502 return parseItemPositionOverflowPosition(propId, important);
1504 case CSSPropertyBorderBottomStyle:
1505 case CSSPropertyBorderCollapse:
1506 case CSSPropertyBorderLeftStyle:
1507 case CSSPropertyBorderRightStyle:
1508 case CSSPropertyBorderTopStyle:
1509 case CSSPropertyBoxSizing:
1510 case CSSPropertyCaptionSide:
1511 case CSSPropertyClear:
1512 case CSSPropertyDirection:
1513 case CSSPropertyDisplay:
1514 case CSSPropertyEmptyCells:
1515 case CSSPropertyFloat:
1516 case CSSPropertyFontStyle:
1517 case CSSPropertyImageRendering:
1518 case CSSPropertyListStylePosition:
1519 case CSSPropertyListStyleType:
1520 case CSSPropertyObjectFit:
1521 case CSSPropertyOutlineStyle:
1522 case CSSPropertyOverflowWrap:
1523 case CSSPropertyOverflowX:
1524 case CSSPropertyOverflowY:
1525 case CSSPropertyPageBreakAfter:
1526 case CSSPropertyPageBreakBefore:
1527 case CSSPropertyPageBreakInside:
1528 case CSSPropertyPointerEvents:
1529 case CSSPropertyPosition:
1530 case CSSPropertyResize:
1531 case CSSPropertySpeak:
1532 case CSSPropertyTableLayout:
1533 case CSSPropertyTextAlignLast:
1534 case CSSPropertyTextJustify:
1535 case CSSPropertyTextLineThroughMode:
1536 case CSSPropertyTextLineThroughStyle:
1537 case CSSPropertyTextOverflow:
1538 case CSSPropertyTextOverlineMode:
1539 case CSSPropertyTextOverlineStyle:
1540 case CSSPropertyTextRendering:
1541 case CSSPropertyTextTransform:
1542 case CSSPropertyTextUnderlineMode:
1543 case CSSPropertyTextUnderlineStyle:
1544 case CSSPropertyTouchActionDelay:
1545 case CSSPropertyVisibility:
1546 case CSSPropertyWebkitAppearance:
1547 case CSSPropertyBackfaceVisibility:
1548 case CSSPropertyWebkitBackfaceVisibility:
1549 case CSSPropertyWebkitBorderAfterStyle:
1550 case CSSPropertyWebkitBorderBeforeStyle:
1551 case CSSPropertyWebkitBorderEndStyle:
1552 case CSSPropertyWebkitBorderFit:
1553 case CSSPropertyWebkitBorderStartStyle:
1554 case CSSPropertyWebkitBoxAlign:
1555 case CSSPropertyWebkitBoxDecorationBreak:
1556 case CSSPropertyWebkitBoxDirection:
1557 case CSSPropertyWebkitBoxLines:
1558 case CSSPropertyWebkitBoxOrient:
1559 case CSSPropertyWebkitBoxPack:
1560 case CSSPropertyInternalCallback:
1561 case CSSPropertyWebkitColumnBreakAfter:
1562 case CSSPropertyWebkitColumnBreakBefore:
1563 case CSSPropertyWebkitColumnBreakInside:
1564 case CSSPropertyColumnFill:
1565 case CSSPropertyWebkitColumnRuleStyle:
1566 case CSSPropertyAlignContent:
1567 case CSSPropertyFlexDirection:
1568 case CSSPropertyFlexWrap:
1569 case CSSPropertyJustifyContent:
1570 case CSSPropertyFontKerning:
1571 case CSSPropertyWebkitFontSmoothing:
1572 case CSSPropertyGridAutoFlow:
1573 case CSSPropertyWebkitLineBreak:
1574 case CSSPropertyWebkitMarginAfterCollapse:
1575 case CSSPropertyWebkitMarginBeforeCollapse:
1576 case CSSPropertyWebkitMarginBottomCollapse:
1577 case CSSPropertyWebkitMarginTopCollapse:
1578 case CSSPropertyInternalMarqueeDirection:
1579 case CSSPropertyInternalMarqueeStyle:
1580 case CSSPropertyWebkitPrintColorAdjust:
1581 case CSSPropertyWebkitRtlOrdering:
1582 case CSSPropertyWebkitRubyPosition:
1583 case CSSPropertyWebkitTextCombine:
1584 case CSSPropertyWebkitTextEmphasisPosition:
1585 case CSSPropertyWebkitTextSecurity:
1586 case CSSPropertyTransformStyle:
1587 case CSSPropertyWebkitTransformStyle:
1588 case CSSPropertyWebkitUserDrag:
1589 case CSSPropertyWebkitUserModify:
1590 case CSSPropertyWebkitUserSelect:
1591 case CSSPropertyWebkitWrapFlow:
1592 case CSSPropertyWebkitWrapThrough:
1593 case CSSPropertyWebkitWritingMode:
1594 case CSSPropertyWhiteSpace:
1595 case CSSPropertyWordBreak:
1596 case CSSPropertyWordWrap:
1597 case CSSPropertyMixBlendMode:
1598 case CSSPropertyIsolation:
1599 // These properties should be handled before in isValidKeywordPropertyAndValue().
1600 ASSERT_NOT_REACHED();
1602 // Properties below are validated inside parseViewportProperty, because we
1603 // check for parser state. We need to invalidate if someone adds them outside
1604 // a @viewport rule.
1605 case CSSPropertyMaxZoom:
1606 case CSSPropertyMinZoom:
1607 case CSSPropertyOrientation:
1608 case CSSPropertyUserZoom:
1609 validPrimitive = false;
1612 case CSSPropertyAll:
1613 if (id == CSSValueInitial || id == CSSValueInherit || id == CSSValueUnset) {
1614 validPrimitive = true;
1620 return parseSVGValue(propId, important);
1623 if (validPrimitive) {
1624 parsedValue = parseValidPrimitive(id, value);
1625 m_valueList->next();
1627 ASSERT(!m_parsedCalculation);
1629 if (!m_valueList->current() || inShorthand()) {
1630 addProperty(propId, parsedValue.release(), important);
1637 void CSSPropertyParser::addFillValue(RefPtrWillBeRawPtr<CSSValue>& lval, PassRefPtrWillBeRawPtr<CSSValue> rval)
1640 if (lval->isBaseValueList())
1641 toCSSValueList(lval.get())->append(rval);
1643 PassRefPtrWillBeRawPtr<CSSValue> oldlVal(lval.release());
1644 PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
1645 list->append(oldlVal);
1654 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtrWillBeRawPtr<CSSValue>& cssValue)
1656 if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
1657 || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
1658 cssValue = cssValuePool().createIdentifierValue(parserValue->id);
1664 const int cMaxFillProperties = 9;
1666 bool CSSPropertyParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
1668 ASSERT(numProperties <= cMaxFillProperties);
1669 if (numProperties > cMaxFillProperties)
1672 ShorthandScope scope(this, propId);
1674 bool parsedProperty[cMaxFillProperties] = { false };
1675 RefPtrWillBeRawPtr<CSSValue> values[cMaxFillProperties];
1677 // Zero initialize the array of raw pointers.
1678 memset(&values, 0, sizeof(values));
1680 RefPtrWillBeRawPtr<CSSValue> clipValue = nullptr;
1681 RefPtrWillBeRawPtr<CSSValue> positionYValue = nullptr;
1682 RefPtrWillBeRawPtr<CSSValue> repeatYValue = nullptr;
1683 bool foundClip = false;
1685 bool foundPositionCSSProperty = false;
1687 while (m_valueList->current()) {
1688 CSSParserValue* val = m_valueList->current();
1689 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
1690 // We hit the end. Fill in all remaining values with the initial value.
1691 m_valueList->next();
1692 for (i = 0; i < numProperties; ++i) {
1693 if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
1694 // Color is not allowed except as the last item in a list for backgrounds.
1695 // Reject the entire property.
1698 if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
1699 addFillValue(values[i], cssValuePool().createImplicitInitialValue());
1700 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1701 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
1702 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1703 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
1704 if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
1705 // If background-origin wasn't present, then reset background-clip also.
1706 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
1709 parsedProperty[i] = false;
1711 if (!m_valueList->current())
1715 bool sizeCSSPropertyExpected = false;
1716 if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
1717 sizeCSSPropertyExpected = true;
1718 m_valueList->next();
1721 foundPositionCSSProperty = false;
1723 for (i = 0; !found && i < numProperties; ++i) {
1725 if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgroundSize && properties[i] != CSSPropertyWebkitMaskSize))
1727 if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgroundSize || properties[i] == CSSPropertyWebkitMaskSize))
1730 if (!parsedProperty[i]) {
1731 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
1732 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
1733 CSSPropertyID propId1, propId2;
1734 CSSParserValue* parserValue = m_valueList->current();
1735 // parseFillProperty() may modify m_implicitShorthand, so we MUST reset it
1736 // before EACH return below.
1737 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
1738 parsedProperty[i] = found = true;
1739 addFillValue(values[i], val1.release());
1740 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1741 addFillValue(positionYValue, val2.release());
1742 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1743 addFillValue(repeatYValue, val2.release());
1744 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
1745 // Reparse the value as a clip, and see if we succeed.
1746 if (parseBackgroundClip(parserValue, val1))
1747 addFillValue(clipValue, val1.release()); // The property parsed successfully.
1749 addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
1751 if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
1753 addFillValue(clipValue, val1.release());
1756 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1757 foundPositionCSSProperty = true;
1762 // if we didn't find at least one match, this is an
1763 // invalid shorthand and we have to ignore it
1765 m_implicitShorthand = false;
1770 // Now add all of the properties we found.
1771 for (i = 0; i < numProperties; i++) {
1772 // Fill in any remaining properties with the initial value.
1773 if (!parsedProperty[i]) {
1774 addFillValue(values[i], cssValuePool().createImplicitInitialValue());
1775 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1776 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
1777 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1778 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
1779 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
1780 // If background-origin wasn't present, then reset background-clip also.
1781 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
1784 if (properties[i] == CSSPropertyBackgroundPosition) {
1785 addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
1786 // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
1787 addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
1788 } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
1789 addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
1790 // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
1791 addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
1792 } else if (properties[i] == CSSPropertyBackgroundRepeat) {
1793 addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
1794 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
1795 addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
1796 } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
1797 addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
1798 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
1799 addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
1800 } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
1801 // Value is already set while updating origin
1803 else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i] && m_context.useLegacyBackgroundSizeShorthandBehavior())
1806 addProperty(properties[i], values[i].release(), important);
1808 // Add in clip values when we hit the corresponding origin property.
1809 if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
1810 addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
1811 else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
1812 addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
1815 m_implicitShorthand = false;
1819 static bool isValidTransitionPropertyList(CSSValueList* value)
1821 if (value->length() < 2)
1823 for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
1824 // FIXME: Shorthand parsing shouldn't add initial to the list since it won't round-trip
1825 if (i.value()->isInitialValue())
1827 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(i.value());
1828 if (primitiveValue->isValueID() && primitiveValue->getValueID() == CSSValueNone)
1834 bool CSSPropertyParser::parseAnimationShorthand(CSSPropertyID propId, bool important)
1836 const StylePropertyShorthand& animationProperties = parsingShorthandForProperty(propId);
1837 const unsigned numProperties = 8;
1839 // The list of properties in the shorthand should be the same
1840 // length as the list with animation name in last position, even though they are
1841 // in a different order.
1842 ASSERT(numProperties == animationProperties.length());
1843 ASSERT(numProperties == shorthandForProperty(propId).length());
1845 ShorthandScope scope(this, propId);
1847 bool parsedProperty[numProperties] = { false };
1848 RefPtrWillBeRawPtr<CSSValueList> values[numProperties];
1849 for (size_t i = 0; i < numProperties; ++i)
1850 values[i] = CSSValueList::createCommaSeparated();
1852 while (m_valueList->current()) {
1853 CSSParserValue* val = m_valueList->current();
1854 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
1855 // We hit the end. Fill in all remaining values with the initial value.
1856 m_valueList->next();
1857 for (size_t i = 0; i < numProperties; ++i) {
1858 if (!parsedProperty[i])
1859 values[i]->append(cssValuePool().createImplicitInitialValue());
1860 parsedProperty[i] = false;
1862 if (!m_valueList->current())
1867 for (size_t i = 0; i < numProperties; ++i) {
1868 if (parsedProperty[i])
1870 if (RefPtrWillBeRawPtr<CSSValue> val = parseAnimationProperty(animationProperties.properties()[i])) {
1871 parsedProperty[i] = found = true;
1872 values[i]->append(val.release());
1877 // if we didn't find at least one match, this is an
1878 // invalid shorthand and we have to ignore it
1883 for (size_t i = 0; i < numProperties; ++i) {
1884 // If we didn't find the property, set an intial value.
1885 if (!parsedProperty[i])
1886 values[i]->append(cssValuePool().createImplicitInitialValue());
1888 if (RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
1889 addPropertyWithPrefixingVariant(animationProperties.properties()[i], values[i].release(), important);
1891 addProperty(animationProperties.properties()[i], values[i].release(), important);
1897 bool CSSPropertyParser::parseTransitionShorthand(CSSPropertyID propId, bool important)
1899 const unsigned numProperties = 4;
1900 const StylePropertyShorthand& shorthand = parsingShorthandForProperty(propId);
1901 ASSERT(numProperties == shorthand.length());
1903 ShorthandScope scope(this, propId);
1905 bool parsedProperty[numProperties] = { false };
1906 RefPtrWillBeRawPtr<CSSValueList> values[numProperties];
1907 for (size_t i = 0; i < numProperties; ++i)
1908 values[i] = CSSValueList::createCommaSeparated();
1910 while (m_valueList->current()) {
1911 CSSParserValue* val = m_valueList->current();
1912 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
1913 // We hit the end. Fill in all remaining values with the initial value.
1914 m_valueList->next();
1915 for (size_t i = 0; i < numProperties; ++i) {
1916 if (!parsedProperty[i])
1917 values[i]->append(cssValuePool().createImplicitInitialValue());
1918 parsedProperty[i] = false;
1920 if (!m_valueList->current())
1925 for (size_t i = 0; i < numProperties; ++i) {
1926 if (parsedProperty[i])
1928 if (RefPtrWillBeRawPtr<CSSValue> val = parseAnimationProperty(shorthand.properties()[i])) {
1929 parsedProperty[i] = found = true;
1930 values[i]->append(val.release());
1935 // if we didn't find at least one match, this is an
1936 // invalid shorthand and we have to ignore it
1941 ASSERT(shorthand.properties()[3] == CSSPropertyTransitionProperty || shorthand.properties()[3] == CSSPropertyWebkitTransitionProperty);
1942 if (!isValidTransitionPropertyList(values[3].get()))
1945 // Fill in any remaining properties with the initial value and add
1946 for (size_t i = 0; i < numProperties; ++i) {
1947 if (!parsedProperty[i])
1948 values[i]->append(cssValuePool().createImplicitInitialValue());
1949 addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].release(), important);
1955 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnWidth()
1957 CSSParserValue* value = m_valueList->current();
1958 // Always parse lengths in strict mode here, since it would be ambiguous otherwise when used in
1959 // the 'columns' shorthand property.
1960 if (value->id == CSSValueAuto
1961 || (validUnit(value, FLength | FNonNeg, HTMLStandardMode) && value->fValue)) {
1962 RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
1963 m_valueList->next();
1969 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnCount()
1971 CSSParserValue* value = m_valueList->current();
1972 if (value->id == CSSValueAuto
1973 || (!value->id && validUnit(value, FPositiveInteger, HTMLQuirksMode))) {
1974 RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
1975 m_valueList->next();
1981 bool CSSPropertyParser::parseColumnsShorthand(bool important)
1983 RefPtrWillBeRawPtr<CSSValue> columnWidth = nullptr;
1984 RefPtrWillBeRawPtr<CSSValue> columnCount = nullptr;
1985 bool hasPendingExplicitAuto = false;
1987 for (unsigned propertiesParsed = 0; CSSParserValue* value = m_valueList->current(); propertiesParsed++) {
1988 if (propertiesParsed >= 2)
1989 return false; // Too many values for this shorthand. Invalid declaration.
1990 if (!propertiesParsed && value->id == CSSValueAuto) {
1991 // 'auto' is a valid value for any of the two longhands, and at this point we
1992 // don't know which one(s) it is meant for. We need to see if there are other
1994 m_valueList->next();
1995 hasPendingExplicitAuto = true;
1998 if ((columnWidth = parseColumnWidth()))
2002 if ((columnCount = parseColumnCount()))
2005 // If we didn't find at least one match, this is an
2006 // invalid shorthand and we have to ignore it.
2010 if (hasPendingExplicitAuto) {
2011 // Time to assign the previously skipped 'auto' value to a property. If both properties are
2012 // unassigned at this point (i.e. 'columns:auto'), it doesn't matter that much which one we
2013 // set (although it does make a slight difference to web-inspector). The one we don't set
2014 // here will get an implicit 'auto' value further down.
2016 columnWidth = cssValuePool().createIdentifierValue(CSSValueAuto);
2018 ASSERT(!columnCount);
2019 columnCount = cssValuePool().createIdentifierValue(CSSValueAuto);
2022 ASSERT(columnCount || columnWidth);
2024 // Any unassigned property at this point will become implicit 'auto'.
2026 addProperty(CSSPropertyWebkitColumnWidth, columnWidth, important);
2028 addProperty(CSSPropertyWebkitColumnWidth, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
2030 addProperty(CSSPropertyWebkitColumnCount, columnCount, important);
2032 addProperty(CSSPropertyWebkitColumnCount, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
2036 bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
2038 // We try to match as many properties as possible
2039 // We set up an array of booleans to mark which property has been found,
2040 // and we try to search for properties until it makes no longer any sense.
2041 ShorthandScope scope(this, propId);
2044 unsigned propertiesParsed = 0;
2045 bool propertyFound[6] = { false, false, false, false, false, false }; // 6 is enough size.
2047 while (m_valueList->current()) {
2049 for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
2050 if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
2051 propertyFound[propIndex] = found = true;
2056 // if we didn't find at least one match, this is an
2057 // invalid shorthand and we have to ignore it
2062 if (propertiesParsed == shorthand.length())
2065 // Fill in any remaining properties with the initial value.
2066 ImplicitScope implicitScope(this, PropertyImplicit);
2067 const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization();
2068 for (unsigned i = 0; i < shorthand.length(); ++i) {
2069 if (propertyFound[i])
2072 if (propertiesForInitialization) {
2073 const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]);
2074 for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
2075 addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
2077 addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
2083 bool CSSPropertyParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties, bool important)
2085 /* From the CSS 2 specs, 8.3
2086 * If there is only one value, it applies to all sides. If there are two values, the top and
2087 * bottom margins are set to the first value and the right and left margins are set to the second.
2088 * If there are three values, the top is set to the first value, the left and right are set to the
2089 * second, and the bottom is set to the third. If there are four values, they apply to the top,
2090 * right, bottom, and left, respectively.
2093 int num = inShorthand() ? 1 : m_valueList->size();
2095 ShorthandScope scope(this, propId);
2097 // the order is top, right, bottom, left
2100 if (!parseValue(properties[0], important))
2102 CSSValue* value = m_parsedProperties.last().value();
2103 ImplicitScope implicitScope(this, PropertyImplicit);
2104 addProperty(properties[1], value, important);
2105 addProperty(properties[2], value, important);
2106 addProperty(properties[3], value, important);
2110 if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
2112 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
2113 ImplicitScope implicitScope(this, PropertyImplicit);
2114 addProperty(properties[2], value, important);
2115 value = m_parsedProperties[m_parsedProperties.size() - 2].value();
2116 addProperty(properties[3], value, important);
2120 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
2122 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
2123 ImplicitScope implicitScope(this, PropertyImplicit);
2124 addProperty(properties[3], value, important);
2128 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
2129 !parseValue(properties[2], important) || !parseValue(properties[3], important))
2141 // auto | <identifier>
2142 bool CSSPropertyParser::parsePage(CSSPropertyID propId, bool important)
2144 ASSERT(propId == CSSPropertyPage);
2146 if (m_valueList->size() != 1)
2149 CSSParserValue* value = m_valueList->current();
2153 if (value->id == CSSValueAuto) {
2154 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
2156 } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
2157 addProperty(propId, createPrimitiveStringValue(value), important);
2163 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
2164 bool CSSPropertyParser::parseSize(CSSPropertyID propId, bool important)
2166 ASSERT(propId == CSSPropertySize);
2168 if (m_valueList->size() > 2)
2171 CSSParserValue* value = m_valueList->current();
2175 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
2178 SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
2179 if (paramType == None)
2182 // Second parameter, if any.
2183 value = m_valueList->next();
2185 paramType = parseSizeParameter(parsedValues.get(), value, paramType);
2186 if (paramType == None)
2190 addProperty(propId, parsedValues.release(), important);
2194 CSSPropertyParser::SizeParameterType CSSPropertyParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
2196 switch (value->id) {
2198 if (prevParamType == None) {
2199 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
2203 case CSSValueLandscape:
2204 case CSSValuePortrait:
2205 if (prevParamType == None || prevParamType == PageSize) {
2206 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
2215 case CSSValueLedger:
2217 case CSSValueLetter:
2218 if (prevParamType == None || prevParamType == Orientation) {
2219 // Normalize to Page Size then Orientation order by prepending.
2220 // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
2221 parsedValues->prepend(cssValuePool().createIdentifierValue(value->id));
2226 if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) {
2227 parsedValues->append(createPrimitiveNumericValue(value));
2236 // [ <string> <string> ]+ | inherit | none
2237 // inherit and none are handled in parseValue.
2238 bool CSSPropertyParser::parseQuotes(CSSPropertyID propId, bool important)
2240 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
2241 while (CSSParserValue* val = m_valueList->current()) {
2242 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
2243 if (val->unit == CSSPrimitiveValue::CSS_STRING)
2244 parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
2247 values->append(parsedValue.release());
2248 m_valueList->next();
2250 if (values->length()) {
2251 addProperty(propId, values.release(), important);
2252 m_valueList->next();
2258 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
2259 // in CSS 2.1 this got somewhat reduced:
2260 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
2261 bool CSSPropertyParser::parseContent(CSSPropertyID propId, bool important)
2263 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
2265 while (CSSParserValue* val = m_valueList->current()) {
2266 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
2267 if (val->unit == CSSPrimitiveValue::CSS_URI) {
2269 parsedValue = createCSSImageValueWithReferrer(val->string, completeURL(val->string));
2270 } else if (val->unit == CSSParserValue::Function) {
2271 // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
2272 CSSParserValueList* args = val->function->args.get();
2275 if (equalIgnoringCase(val->function->name, "attr(")) {
2276 parsedValue = parseAttr(args);
2279 } else if (equalIgnoringCase(val->function->name, "counter(")) {
2280 parsedValue = parseCounterContent(args, false);
2283 } else if (equalIgnoringCase(val->function->name, "counters(")) {
2284 parsedValue = parseCounterContent(args, true);
2287 } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
2288 parsedValue = parseImageSet(m_valueList.get());
2291 } else if (isGeneratedImageValue(val)) {
2292 if (!parseGeneratedImage(m_valueList.get(), parsedValue))
2296 } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
2302 // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
2306 case CSSValueOpenQuote:
2307 case CSSValueCloseQuote:
2308 case CSSValueNoOpenQuote:
2309 case CSSValueNoCloseQuote:
2311 case CSSValueNormal:
2312 parsedValue = cssValuePool().createIdentifierValue(val->id);
2316 } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
2317 parsedValue = createPrimitiveStringValue(val);
2321 values->append(parsedValue.release());
2322 m_valueList->next();
2325 if (values->length()) {
2326 addProperty(propId, values.release(), important);
2327 m_valueList->next();
2334 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAttr(CSSParserValueList* args)
2336 if (args->size() != 1)
2339 CSSParserValue* a = args->current();
2341 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
2344 String attrName = a->string;
2345 // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
2346 // But HTML attribute names can't have those characters, and we should not
2347 // even parse them inside attr().
2348 if (attrName[0] == '-')
2351 if (m_context.isHTMLDocument())
2352 attrName = attrName.lower();
2354 return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
2357 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBackgroundColor()
2359 CSSValueID id = m_valueList->current()->id;
2360 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
2361 (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
2362 return cssValuePool().createIdentifierValue(id);
2363 return parseColor();
2366 bool CSSPropertyParser::parseFillImage(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value)
2368 if (valueList->current()->id == CSSValueNone) {
2369 value = cssValuePool().createIdentifierValue(CSSValueNone);
2372 if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
2373 value = createCSSImageValueWithReferrer(valueList->current()->string, completeURL(valueList->current()->string));
2377 if (isGeneratedImageValue(valueList->current()))
2378 return parseGeneratedImage(valueList, value);
2380 if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) {
2381 value = parseImageSet(m_valueList.get());
2389 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionX(CSSParserValueList* valueList)
2391 int id = valueList->current()->id;
2392 if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
2394 if (id == CSSValueRight)
2396 else if (id == CSSValueCenter)
2398 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2400 if (validUnit(valueList->current(), FPercent | FLength))
2401 return createPrimitiveNumericValue(valueList->current());
2405 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionY(CSSParserValueList* valueList)
2407 int id = valueList->current()->id;
2408 if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
2410 if (id == CSSValueBottom)
2412 else if (id == CSSValueCenter)
2414 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2416 if (validUnit(valueList->current(), FPercent | FLength))
2417 return createPrimitiveNumericValue(valueList->current());
2421 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode)
2423 CSSValueID id = valueList->current()->id;
2424 if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
2426 if (id == CSSValueLeft || id == CSSValueRight) {
2427 if (cumulativeFlags & XFillPosition)
2429 cumulativeFlags |= XFillPosition;
2430 individualFlag = XFillPosition;
2431 if (id == CSSValueRight)
2434 else if (id == CSSValueTop || id == CSSValueBottom) {
2435 if (cumulativeFlags & YFillPosition)
2437 cumulativeFlags |= YFillPosition;
2438 individualFlag = YFillPosition;
2439 if (id == CSSValueBottom)
2441 } else if (id == CSSValueCenter) {
2442 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
2444 cumulativeFlags |= AmbiguousFillPosition;
2445 individualFlag = AmbiguousFillPosition;
2448 if (parsingMode == ResolveValuesAsKeyword)
2449 return cssValuePool().createIdentifierValue(id);
2451 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2453 if (validUnit(valueList->current(), FPercent | FLength)) {
2454 if (!cumulativeFlags) {
2455 cumulativeFlags |= XFillPosition;
2456 individualFlag = XFillPosition;
2457 } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
2458 cumulativeFlags |= YFillPosition;
2459 individualFlag = YFillPosition;
2461 if (m_parsedCalculation)
2462 m_parsedCalculation.release();
2465 return createPrimitiveNumericValue(valueList->current());
2470 static bool isValueConflictingWithCurrentEdge(int value1, int value2)
2472 if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSValueLeft || value2 == CSSValueRight))
2475 if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSValueTop || value2 == CSSValueBottom))
2481 static bool isFillPositionKeyword(CSSValueID value)
2483 return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter;
2486 void CSSPropertyParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2)
2488 // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <percentage> | <length> ]
2489 // In the case of 4 values <position> requires the second value to be a length or a percentage.
2490 if (isFillPositionKeyword(parsedValue2->getValueID()))
2493 unsigned cumulativeFlags = 0;
2494 FillPositionFlag value3Flag = InvalidFillPosition;
2495 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
2499 CSSValueID ident1 = parsedValue1->getValueID();
2500 CSSValueID ident3 = value3->getValueID();
2502 if (ident1 == CSSValueCenter)
2505 if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
2508 // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
2509 // needed as the second call to parseFillPositionComponent was on purpose not checking it. In the
2510 // case of two values top 20px is invalid but in the case of 4 values it becomes valid.
2511 if (isValueConflictingWithCurrentEdge(ident1, ident3))
2516 cumulativeFlags = 0;
2517 FillPositionFlag value4Flag = InvalidFillPosition;
2518 RefPtrWillBeRawPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(valueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
2522 // 4th value must be a length or a percentage.
2523 if (isFillPositionKeyword(value4->getValueID()))
2526 value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
2527 value2 = createPrimitiveValuePair(value3, value4);
2529 if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
2530 value1.swap(value2);
2534 void CSSPropertyParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2)
2536 unsigned cumulativeFlags = 0;
2537 FillPositionFlag value3Flag = InvalidFillPosition;
2538 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
2540 // value3 is not an expected value, we return.
2546 bool swapNeeded = false;
2547 CSSValueID ident1 = parsedValue1->getValueID();
2548 CSSValueID ident2 = parsedValue2->getValueID();
2549 CSSValueID ident3 = value3->getValueID();
2551 CSSValueID firstPositionKeyword;
2552 CSSValueID secondPositionKeyword;
2554 if (ident1 == CSSValueCenter) {
2555 // <position> requires the first 'center' to be followed by a keyword.
2556 if (!isFillPositionKeyword(ident2))
2559 // If 'center' is the first keyword then the last one needs to be a length.
2560 if (isFillPositionKeyword(ident3))
2563 firstPositionKeyword = CSSValueLeft;
2564 if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
2565 firstPositionKeyword = CSSValueTop;
2568 value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
2569 value2 = createPrimitiveValuePair(parsedValue2, value3);
2570 } else if (ident3 == CSSValueCenter) {
2571 if (isFillPositionKeyword(ident2))
2574 secondPositionKeyword = CSSValueTop;
2575 if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
2576 secondPositionKeyword = CSSValueLeft;
2579 value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
2580 value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
2582 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstPositionValue = nullptr;
2583 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondPositionValue = nullptr;
2585 if (isFillPositionKeyword(ident2)) {
2586 // To match CSS grammar, we should only accept: [ center | left | right | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ].
2587 ASSERT(ident2 != CSSValueCenter);
2589 if (isFillPositionKeyword(ident3))
2592 secondPositionValue = value3;
2593 secondPositionKeyword = ident2;
2594 firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
2596 // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
2597 if (!isFillPositionKeyword(ident3))
2600 firstPositionValue = parsedValue2;
2601 secondPositionKeyword = ident3;
2602 secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
2605 if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
2608 value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue);
2609 value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue);
2612 if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
2613 value1.swap(value2);
2616 CSSPrimitiveValue* first = toCSSPrimitiveValue(value1.get());
2617 CSSPrimitiveValue* second = toCSSPrimitiveValue(value2.get());
2618 ident1 = first->getPairValue()->first()->getValueID();
2619 ident2 = second->getPairValue()->first()->getValueID();
2620 ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
2621 ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
2625 inline bool CSSPropertyParser::isPotentialPositionValue(CSSParserValue* value)
2627 return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue);
2630 void CSSPropertyParser::parseFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
2632 unsigned numberOfValues = 0;
2633 for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++numberOfValues) {
2634 CSSParserValue* current = valueList->valueAt(i);
2635 if (isComma(current) || !current || isForwardSlashOperator(current) || !isPotentialPositionValue(current))
2639 if (numberOfValues > 4)
2642 // If we are parsing two values, we can safely call the CSS 2.1 parsing function and return.
2643 if (numberOfValues <= 2) {
2644 parse2ValuesFillPosition(valueList, value1, value2);
2648 ASSERT(numberOfValues > 2 && numberOfValues <= 4);
2650 CSSParserValue* value = valueList->current();
2652 // <position> requires the first value to be a background keyword.
2653 if (!isFillPositionKeyword(value->id))
2656 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
2657 unsigned cumulativeFlags = 0;
2658 FillPositionFlag value1Flag = InvalidFillPosition;
2659 FillPositionFlag value2Flag = InvalidFillPosition;
2660 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
2666 // In case we are parsing more than two values, relax the check inside of parseFillPositionComponent. top 20px is
2667 // a valid start for <position>.
2668 cumulativeFlags = AmbiguousFillPosition;
2669 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
2677 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(value1.get());
2678 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(value2.get());
2683 // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
2684 if (parsedValue2->getValueID() == CSSValueCenter)
2687 if (numberOfValues == 3)
2688 parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
2690 parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
2693 void CSSPropertyParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
2695 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
2696 unsigned cumulativeFlags = 0;
2697 FillPositionFlag value1Flag = InvalidFillPosition;
2698 FillPositionFlag value2Flag = InvalidFillPosition;
2699 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
2703 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
2704 // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the
2705 // value was explicitly specified for our property.
2706 CSSParserValue* value = valueList->next();
2708 // First check for the comma. If so, we are finished parsing this value or value pair.
2713 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
2717 if (!inShorthand()) {
2725 // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
2726 // is simply 50%. This is our default.
2727 // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
2728 // For left/right/center, the default of 50% in the y is still correct.
2729 value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
2731 if (value1Flag == YFillPosition || value2Flag == XFillPosition)
2732 value1.swap(value2);
2735 void CSSPropertyParser::parseFillRepeat(RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
2737 CSSValueID id = m_valueList->current()->id;
2738 if (id == CSSValueRepeatX) {
2739 m_implicitShorthand = true;
2740 value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
2741 value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
2742 m_valueList->next();
2745 if (id == CSSValueRepeatY) {
2746 m_implicitShorthand = true;
2747 value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
2748 value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
2749 m_valueList->next();
2752 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
2753 value1 = cssValuePool().createIdentifierValue(id);
2759 CSSParserValue* value = m_valueList->next();
2761 // Parse the second value if one is available
2762 if (value && !isComma(value)) {
2764 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
2765 value2 = cssValuePool().createIdentifierValue(id);
2766 m_valueList->next();
2771 // If only one value was specified, value2 is the same as value1.
2772 m_implicitShorthand = true;
2773 value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get())->getValueID());
2776 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
2779 CSSParserValue* value = m_valueList->current();
2781 if (value->id == CSSValueContain || value->id == CSSValueCover)
2782 return cssValuePool().createIdentifierValue(value->id);
2784 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = nullptr;
2786 if (value->id == CSSValueAuto)
2787 parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
2789 if (!validUnit(value, FLength | FPercent))
2791 parsedValue1 = createPrimitiveNumericValue(value);
2794 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr;
2795 if ((value = m_valueList->next())) {
2796 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
2798 else if (value->id != CSSValueAuto) {
2799 if (!validUnit(value, FLength | FPercent)) {
2802 // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
2803 m_valueList->previous();
2805 parsedValue2 = createPrimitiveNumericValue(value);
2807 } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
2808 // For backwards compatibility we set the second value to the first if it is omitted.
2809 // We only need to do this for -webkit-background-size. It should be safe to let masks match
2810 // the real property.
2811 parsedValue2 = parsedValue1;
2815 return parsedValue1;
2817 Pair::IdenticalValuesPolicy policy = propId == CSSPropertyWebkitBackgroundSize ?
2818 Pair::DropIdenticalValues : Pair::KeepIdenticalValues;
2820 return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release(), policy);
2823 bool CSSPropertyParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
2824 RefPtrWillBeRawPtr<CSSValue>& retValue1, RefPtrWillBeRawPtr<CSSValue>& retValue2)
2826 RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
2827 RefPtrWillBeRawPtr<CSSValueList> values2 = nullptr;
2828 CSSParserValue* val;
2829 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
2830 RefPtrWillBeRawPtr<CSSValue> value2 = nullptr;
2832 bool allowComma = false;
2834 retValue1 = retValue2 = nullptr;
2837 if (propId == CSSPropertyBackgroundPosition) {
2838 propId1 = CSSPropertyBackgroundPositionX;
2839 propId2 = CSSPropertyBackgroundPositionY;
2840 } else if (propId == CSSPropertyWebkitMaskPosition) {
2841 propId1 = CSSPropertyWebkitMaskPositionX;
2842 propId2 = CSSPropertyWebkitMaskPositionY;
2843 } else if (propId == CSSPropertyBackgroundRepeat) {
2844 propId1 = CSSPropertyBackgroundRepeatX;
2845 propId2 = CSSPropertyBackgroundRepeatY;
2846 } else if (propId == CSSPropertyWebkitMaskRepeat) {
2847 propId1 = CSSPropertyWebkitMaskRepeatX;
2848 propId2 = CSSPropertyWebkitMaskRepeatY;
2851 while ((val = m_valueList->current())) {
2852 RefPtrWillBeRawPtr<CSSValue> currValue = nullptr;
2853 RefPtrWillBeRawPtr<CSSValue> currValue2 = nullptr;
2858 m_valueList->next();
2863 case CSSPropertyBackgroundColor:
2864 currValue = parseBackgroundColor();
2866 m_valueList->next();
2868 case CSSPropertyBackgroundAttachment:
2869 if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
2870 currValue = cssValuePool().createIdentifierValue(val->id);
2871 m_valueList->next();
2874 case CSSPropertyBackgroundImage:
2875 case CSSPropertyWebkitMaskImage:
2876 if (parseFillImage(m_valueList.get(), currValue))
2877 m_valueList->next();
2879 case CSSPropertyWebkitBackgroundClip:
2880 case CSSPropertyWebkitBackgroundOrigin:
2881 case CSSPropertyWebkitMaskClip:
2882 case CSSPropertyWebkitMaskOrigin:
2883 // The first three values here are deprecated and do not apply to the version of the property that has
2884 // the -webkit- prefix removed.
2885 if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
2886 val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
2887 ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
2888 (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
2889 currValue = cssValuePool().createIdentifierValue(val->id);
2890 m_valueList->next();
2893 case CSSPropertyBackgroundClip:
2894 if (parseBackgroundClip(val, currValue))
2895 m_valueList->next();
2897 case CSSPropertyBackgroundOrigin:
2898 if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
2899 currValue = cssValuePool().createIdentifierValue(val->id);
2900 m_valueList->next();
2903 case CSSPropertyBackgroundPosition:
2904 case CSSPropertyWebkitMaskPosition:
2905 parseFillPosition(m_valueList.get(), currValue, currValue2);
2906 // parseFillPosition advances the m_valueList pointer.
2908 case CSSPropertyBackgroundPositionX:
2909 case CSSPropertyWebkitMaskPositionX: {
2910 currValue = parseFillPositionX(m_valueList.get());
2912 m_valueList->next();
2915 case CSSPropertyBackgroundPositionY:
2916 case CSSPropertyWebkitMaskPositionY: {
2917 currValue = parseFillPositionY(m_valueList.get());
2919 m_valueList->next();
2922 case CSSPropertyWebkitBackgroundComposite:
2923 case CSSPropertyWebkitMaskComposite:
2924 if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) {
2925 currValue = cssValuePool().createIdentifierValue(val->id);
2926 m_valueList->next();
2929 case CSSPropertyBackgroundBlendMode:
2930 if (val->id == CSSValueNormal || val->id == CSSValueMultiply
2931 || val->id == CSSValueScreen || val->id == CSSValueOverlay || val->id == CSSValueDarken
2932 || val->id == CSSValueLighten || val->id == CSSValueColorDodge || val->id == CSSValueColorBurn
2933 || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference
2934 || val->id == CSSValueExclusion || val->id == CSSValueHue || val->id == CSSValueSaturation
2935 || val->id == CSSValueColor || val->id == CSSValueLuminosity) {
2936 currValue = cssValuePool().createIdentifierValue(val->id);
2937 m_valueList->next();
2940 case CSSPropertyBackgroundRepeat:
2941 case CSSPropertyWebkitMaskRepeat:
2942 parseFillRepeat(currValue, currValue2);
2943 // parseFillRepeat advances the m_valueList pointer
2945 case CSSPropertyBackgroundSize:
2946 case CSSPropertyWebkitBackgroundSize:
2947 case CSSPropertyWebkitMaskSize: {
2948 currValue = parseFillSize(propId, allowComma);
2950 m_valueList->next();
2953 case CSSPropertyMaskSourceType: {
2954 if (RuntimeEnabledFeatures::cssMaskSourceTypeEnabled()) {
2955 if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id == CSSValueLuminance) {
2956 currValue = cssValuePool().createIdentifierValue(val->id);
2957 m_valueList->next();
2959 currValue = nullptr;
2970 if (value && !values) {
2971 values = CSSValueList::createCommaSeparated();
2972 values->append(value.release());
2975 if (value2 && !values2) {
2976 values2 = CSSValueList::createCommaSeparated();
2977 values2->append(value2.release());
2981 values->append(currValue.release());
2983 value = currValue.release();
2986 values2->append(currValue2.release());
2988 value2 = currValue2.release();
2992 // When parsing any fill shorthand property, we let it handle building up the lists for all
2998 if (values && values->length()) {
2999 retValue1 = values.release();
3000 if (values2 && values2->length())
3001 retValue2 = values2.release();
3005 retValue1 = value.release();
3006 retValue2 = value2.release();
3012 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDelay()
3014 CSSParserValue* value = m_valueList->current();
3015 if (validUnit(value, FTime))
3016 return createPrimitiveNumericValue(value);
3020 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDirection()
3022 CSSParserValue* value = m_valueList->current();
3023 if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
3024 return cssValuePool().createIdentifierValue(value->id);
3028 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDuration()
3030 CSSParserValue* value = m_valueList->current();
3031 if (validUnit(value, FTime | FNonNeg))
3032 return createPrimitiveNumericValue(value);
3036 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationFillMode()
3038 CSSParserValue* value = m_valueList->current();
3039 if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
3040 return cssValuePool().createIdentifierValue(value->id);
3044 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationIterationCount()
3046 CSSParserValue* value = m_valueList->current();
3047 if (value->id == CSSValueInfinite)
3048 return cssValuePool().createIdentifierValue(value->id);
3049 if (validUnit(value, FNumber | FNonNeg))
3050 return createPrimitiveNumericValue(value);
3054 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationName()
3056 CSSParserValue* value = m_valueList->current();
3057 if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
3058 if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value, "none"))) {
3059 return cssValuePool().createIdentifierValue(CSSValueNone);
3061 return createPrimitiveStringValue(value);
3067 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationPlayState()
3069 CSSParserValue* value = m_valueList->current();
3070 if (value->id == CSSValueRunning || value->id == CSSValuePaused)
3071 return cssValuePool().createIdentifierValue(value->id);
3075 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationProperty()
3077 CSSParserValue* value = m_valueList->current();
3078 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
3080 // Since all is valid css property keyword, cssPropertyID for all
3081 // returns non-null value. We need to check "all" before
3082 // cssPropertyID check.
3083 if (equalIgnoringCase(value, "all"))
3084 return cssValuePool().createIdentifierValue(CSSValueAll);
3085 CSSPropertyID result = cssPropertyID(value->string);
3086 if (result && RuntimeCSSEnabled::isCSSPropertyEnabled(result))
3087 return cssValuePool().createIdentifierValue(result);
3088 if (equalIgnoringCase(value, "none"))
3089 return cssValuePool().createIdentifierValue(CSSValueNone);
3090 if (equalIgnoringCase(value, "inherit") || equalIgnoringCase(value, "initial"))
3092 return createPrimitiveStringValue(value);
3095 bool CSSPropertyParser::parseWebkitTransformOriginShorthand(RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, RefPtrWillBeRawPtr<CSSValue>& value3)
3097 parse2ValuesFillPosition(m_valueList.get(), value1, value2);
3100 if (m_valueList->current()) {
3101 if (validUnit(m_valueList->current(), FLength)) {
3102 value3 = createPrimitiveNumericValue(m_valueList->current());
3103 m_valueList->next();
3108 value3 = cssValuePool().createImplicitInitialValue();
3112 bool CSSPropertyParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
3114 CSSParserValue* v = args->current();
3115 if (!validUnit(v, FNumber))
3120 // The last number in the function has no comma after it, so we're done.
3128 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationTimingFunction()
3130 CSSParserValue* value = m_valueList->current();
3131 if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
3132 || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd
3133 || (value->id == CSSValueStepMiddle && RuntimeEnabledFeatures::webAnimationsElementAnimateEnabled()))
3134 return cssValuePool().createIdentifierValue(value->id);
3136 // We must be a function.
3137 if (value->unit != CSSParserValue::Function)
3140 CSSParserValueList* args = value->function->args.get();
3142 if (equalIgnoringCase(value->function->name, "steps(")) {
3143 // For steps, 1 or 2 params must be specified (comma-separated)
3144 if (!args || (args->size() != 1 && args->size() != 3))
3147 // There are two values.
3149 StepsTimingFunction::StepAtPosition stepAtPosition = StepsTimingFunction::StepAtEnd;
3151 CSSParserValue* v = args->current();
3152 if (!validUnit(v, FInteger))
3154 numSteps = clampToInteger(v->fValue);
3160 // There is a comma so we need to parse the second value
3165 case CSSValueMiddle:
3166 if (!RuntimeEnabledFeatures::webAnimationsAPIEnabled())
3168 stepAtPosition = StepsTimingFunction::StepAtMiddle;
3171 stepAtPosition = StepsTimingFunction::StepAtStart;
3174 stepAtPosition = StepsTimingFunction::StepAtEnd;
3181 return CSSStepsTimingFunctionValue::create(numSteps, stepAtPosition);
3184 if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
3185 // For cubic bezier, 4 values must be specified.
3186 if (!args || args->size() != 7)
3189 // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range.
3190 double x1, y1, x2, y2;
3192 if (!parseCubicBezierTimingFunctionValue(args, x1))
3194 if (x1 < 0 || x1 > 1)
3196 if (!parseCubicBezierTimingFunctionValue(args, y1))
3198 if (!parseCubicBezierTimingFunctionValue(args, x2))
3200 if (x2 < 0 || x2 > 1)
3202 if (!parseCubicBezierTimingFunctionValue(args, y2))
3205 return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
3211 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationProperty(CSSPropertyID propId)
3213 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
3215 case CSSPropertyAnimationDelay:
3216 case CSSPropertyWebkitAnimationDelay:
3217 case CSSPropertyTransitionDelay:
3218 case CSSPropertyWebkitTransitionDelay:
3219 value = parseAnimationDelay();
3221 case CSSPropertyAnimationDirection:
3222 case CSSPropertyWebkitAnimationDirection:
3223 value = parseAnimationDirection();
3225 case CSSPropertyAnimationDuration:
3226 case CSSPropertyWebkitAnimationDuration:
3227 case CSSPropertyTransitionDuration:
3228 case CSSPropertyWebkitTransitionDuration:
3229 value = parseAnimationDuration();
3231 case CSSPropertyAnimationFillMode:
3232 case CSSPropertyWebkitAnimationFillMode:
3233 value = parseAnimationFillMode();
3235 case CSSPropertyAnimationIterationCount:
3236 case CSSPropertyWebkitAnimationIterationCount:
3237 value = parseAnimationIterationCount();
3239 case CSSPropertyAnimationName:
3240 case CSSPropertyWebkitAnimationName:
3241 value = parseAnimationName();
3243 case CSSPropertyAnimationPlayState:
3244 case CSSPropertyWebkitAnimationPlayState:
3245 value = parseAnimationPlayState();
3247 case CSSPropertyTransitionProperty:
3248 case CSSPropertyWebkitTransitionProperty:
3249 value = parseAnimationProperty();
3251 case CSSPropertyAnimationTimingFunction:
3252 case CSSPropertyWebkitAnimationTimingFunction:
3253 case CSSPropertyTransitionTimingFunction:
3254 case CSSPropertyWebkitTransitionTimingFunction:
3255 value = parseAnimationTimingFunction();
3258 ASSERT_NOT_REACHED();
3263 m_valueList->next();
3264 return value.release();
3267 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseAnimationPropertyList(CSSPropertyID propId)
3269 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
3270 while (m_valueList->current()) {
3271 RefPtrWillBeRawPtr<CSSValue> value = parseAnimationProperty(propId);
3274 list->append(value.release());
3275 if (CSSParserValue* parserValue = m_valueList->current()) {
3276 if (!isComma(parserValue))
3278 m_valueList->next();
3279 ASSERT(m_valueList->current());
3282 if ((propId == CSSPropertyTransitionProperty || propId == CSSPropertyWebkitTransitionProperty) && !isValidTransitionPropertyList(list.get()))
3284 ASSERT(list->length());
3285 return list.release();
3288 static inline bool isCSSWideKeyword(CSSParserValue& value)
3290 return value.id == CSSValueInitial || value.id == CSSValueInherit || value.id == CSSValueDefault;
3293 static inline bool isValidCustomIdentForGridPositions(CSSParserValue& value)
3295 // FIXME: we need a more general solution for <custom-ident> in all properties.
3296 return value.unit == CSSPrimitiveValue::CSS_IDENT && value.id != CSSValueSpan && value.id != CSSValueAuto && !isCSSWideKeyword(value);
3299 // The function parses [ <integer> || <custom-ident> ] in <grid-line> (which can be stand alone or with 'span').
3300 bool CSSPropertyParser::parseIntegerOrCustomIdentFromGridPosition(RefPtrWillBeRawPtr<CSSPrimitiveValue>& numericValue, RefPtrWillBeRawPtr<CSSPrimitiveValue>& gridLineName)
3302 CSSParserValue* value = m_valueList->current();
3303 if (validUnit(value, FInteger) && value->fValue) {
3304 numericValue = createPrimitiveNumericValue(value);
3305 value = m_valueList->next();
3306 if (value && isValidCustomIdentForGridPositions(*value)) {
3307 gridLineName = createPrimitiveStringValue(m_valueList->current());
3308 m_valueList->next();
3313 if (isValidCustomIdentForGridPositions(*value)) {
3314 gridLineName = createPrimitiveStringValue(m_valueList->current());
3315 value = m_valueList->next();
3316 if (value && validUnit(value, FInteger) && value->fValue) {
3317 numericValue = createPrimitiveNumericValue(value);
3318 m_valueList->next();
3326 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridPosition()
3328 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3330 CSSParserValue* value = m_valueList->current();
3331 if (value->id == CSSValueAuto) {
3332 m_valueList->next();
3333 return cssValuePool().createIdentifierValue(CSSValueAuto);
3336 RefPtrWillBeRawPtr<CSSPrimitiveValue> numericValue = nullptr;
3337 RefPtrWillBeRawPtr<CSSPrimitiveValue> gridLineName = nullptr;
3338 bool hasSeenSpanKeyword = false;
3340 if (parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName)) {
3341 value = m_valueList->current();
3342 if (value && value->id == CSSValueSpan) {
3343 hasSeenSpanKeyword = true;
3344 m_valueList->next();
3346 } else if (value->id == CSSValueSpan) {
3347 hasSeenSpanKeyword = true;
3348 if (CSSParserValue* nextValue = m_valueList->next()) {
3349 if (!isForwardSlashOperator(nextValue) && !parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName))
3354 // Check that we have consumed all the value list. For shorthands, the parser will pass
3355 // the whole value list (including the opposite position).
3356 if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current()))
3359 // If we didn't parse anything, this is not a valid grid position.
3360 if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
3363 // Negative numbers are not allowed for span (but are for <integer>).
3364 if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
3367 // For the <custom-ident> case.
3368 if (gridLineName && !numericValue && !hasSeenSpanKeyword)
3369 return cssValuePool().createValue(gridLineName->getStringValue(), CSSPrimitiveValue::CSS_STRING);
3371 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
3372 if (hasSeenSpanKeyword)
3373 values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
3375 values->append(numericValue.release());
3377 values->append(gridLineName.release());
3378 ASSERT(values->length());
3379 return values.release();
3382 static PassRefPtrWillBeRawPtr<CSSValue> gridMissingGridPositionValue(CSSValue* value)
3384 if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isString())
3387 return cssValuePool().createIdentifierValue(CSSValueAuto);
3390 bool CSSPropertyParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
3392 ShorthandScope scope(this, shorthandId);
3393 const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
3394 ASSERT(shorthand.length() == 2);
3396 RefPtrWillBeRawPtr<CSSValue> startValue = parseGridPosition();
3400 RefPtrWillBeRawPtr<CSSValue> endValue = nullptr;
3401 if (m_valueList->current()) {
3402 if (!isForwardSlashOperator(m_valueList->current()))
3405 if (!m_valueList->next())
3408 endValue = parseGridPosition();
3409 if (!endValue || m_valueList->current())
3412 endValue = gridMissingGridPositionValue(startValue.get());
3415 addProperty(shorthand.properties()[0], startValue, important);
3416 addProperty(shorthand.properties()[1], endValue, important);
3420 bool CSSPropertyParser::parseGridTemplateRowsAndAreas(PassRefPtrWillBeRawPtr<CSSValue> templateColumns, bool important)
3422 NamedGridAreaMap gridAreaMap;
3423 size_t rowCount = 0;
3424 size_t columnCount = 0;
3425 bool trailingIdentWasAdded = false;
3426 RefPtrWillBeRawPtr<CSSValueList> templateRows = CSSValueList::createSpaceSeparated();
3428 // At least template-areas strings must be defined.
3429 if (!m_valueList->current())
3432 while (m_valueList->current()) {
3433 // Handle leading <custom-ident>*.
3434 if (m_valueList->current()->unit == CSSParserValue::ValueList) {
3435 if (trailingIdentWasAdded) {
3436 // A row's trailing ident must be concatenated with the next row's leading one.
3437 parseGridLineNames(*m_valueList, *templateRows, static_cast<CSSGridLineNamesValue*>(templateRows->item(templateRows->length() - 1)));
3439 parseGridLineNames(*m_valueList, *templateRows);
3443 // Handle a template-area's row.
3444 if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
3448 // Handle template-rows's track-size.
3449 if (m_valueList->current() && m_valueList->current()->unit != CSSParserValue::ValueList && m_valueList->current()->unit != CSSPrimitiveValue::CSS_STRING) {
3450 RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
3453 templateRows->append(value);
3455 templateRows->append(cssValuePool().createIdentifierValue(CSSValueAuto));
3458 // This will handle the trailing/leading <custom-ident>* in the grammar.
3459 trailingIdentWasAdded = false;
3460 if (m_valueList->current() && m_valueList->current()->unit == CSSParserValue::ValueList) {
3461 parseGridLineNames(*m_valueList, *templateRows);
3462 trailingIdentWasAdded = true;
3466 // [<track-list> /]?
3467 if (templateColumns)
3468 addProperty(CSSPropertyGridTemplateColumns, templateColumns, important);
3470 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createIdentifierValue(CSSValueNone), important);
3472 // [<line-names>? <string> [<track-size> <line-names>]? ]+
3473 RefPtrWillBeRawPtr<CSSValue> templateAreas = CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
3474 addProperty(CSSPropertyGridTemplateAreas, templateAreas.release(), important);
3475 addProperty(CSSPropertyGridTemplateRows, templateRows.release(), important);
3482 bool CSSPropertyParser::parseGridTemplateShorthand(bool important)
3484 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3486 ShorthandScope scope(this, CSSPropertyGridTemplate);
3487 ASSERT(gridTemplateShorthand().length() == 3);
3489 // At least "none" must be defined.
3490 if (!m_valueList->current())
3493 bool firstValueIsNone = m_valueList->current()->id == CSSValueNone;
3496 if (firstValueIsNone && !m_valueList->next()) {
3497 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createIdentifierValue(CSSValueNone), important);
3498 addProperty(CSSPropertyGridTemplateRows, cssValuePool().createIdentifierValue(CSSValueNone), important);
3499 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifierValue(CSSValueNone), important);
3504 RefPtrWillBeRawPtr<CSSValue> columnsValue = nullptr;
3505 if (firstValueIsNone) {
3506 columnsValue = cssValuePool().createIdentifierValue(CSSValueNone);
3508 columnsValue = parseGridTrackList(important);
3511 // 2- <grid-template-columns> / <grid-template-columns> syntax.
3513 if (!(m_valueList->current() && isForwardSlashOperator(m_valueList->current()) && m_valueList->next()))
3515 index = m_valueList->currentIndex();
3516 if (RefPtrWillBeRawPtr<CSSValue> rowsValue = parseGridTrackList(important)) {
3517 if (m_valueList->current())
3519 addProperty(CSSPropertyGridTemplateColumns, columnsValue, important);
3520 addProperty(CSSPropertyGridTemplateRows, rowsValue, important);
3521 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifierValue(CSSValueNone), important);
3527 // 3- [<track-list> /]? [<line-names>? <string> [<track-size> <line-names>]? ]+ syntax.
3528 // The template-columns <track-list> can't be 'none'.
3529 if (firstValueIsNone)
3531 // It requires to rewind parsing due to previous syntax failures.
3532 m_valueList->setCurrentIndex(index);
3533 return parseGridTemplateRowsAndAreas(columnsValue, important);
3536 bool CSSPropertyParser::parseGridShorthand(bool important)
3538 ShorthandScope scope(this, CSSPropertyGrid);
3539 ASSERT(shorthandForProperty(CSSPropertyGrid).length() == 4);
3541 // 1- <grid-template>
3542 if (parseGridTemplateShorthand(important)) {
3543 // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
3544 // The sub-properties not specified are set to their initial value, as normal for shorthands.
3545 addProperty(CSSPropertyGridAutoFlow, cssValuePool().createImplicitInitialValue(), important);
3546 addProperty(CSSPropertyGridAutoColumns, cssValuePool().createImplicitInitialValue(), important);
3547 addProperty(CSSPropertyGridAutoRows, cssValuePool().createImplicitInitialValue(), important);
3551 // Need to rewind parsing to explore the alternative syntax of this shorthand.
3552 m_valueList->setCurrentIndex(0);
3554 // 2- <grid-auto-flow> [ <grid-auto-columns> [ / <grid-auto-rows> ]? ]
3555 CSSValueID id = m_valueList->current()->id;
3556 if (id != CSSValueRow && id != CSSValueColumn && id != CSSValueNone)
3559 RefPtrWillBeRawPtr<CSSValue> autoFlowValue = cssValuePool().createIdentifierValue(id);
3560 RefPtrWillBeRawPtr<CSSValue> autoColumnsValue = nullptr;
3561 RefPtrWillBeRawPtr<CSSValue> autoRowsValue = nullptr;
3563 if (m_valueList->next()) {
3564 autoColumnsValue = parseGridTrackSize(*m_valueList);
3565 if (!autoColumnsValue)
3567 if (m_valueList->current()) {
3568 if (!isForwardSlashOperator(m_valueList->current()) || !m_valueList->next())
3570 autoRowsValue = parseGridTrackSize(*m_valueList);
3574 if (m_valueList->current())
3577 // Other omitted values are set to their initial values.
3578 autoColumnsValue = cssValuePool().createImplicitInitialValue();
3579 autoRowsValue = cssValuePool().createImplicitInitialValue();
3582 // if <grid-auto-rows> value is omitted, it is set to the value specified for grid-auto-columns.
3584 autoRowsValue = autoColumnsValue;
3586 addProperty(CSSPropertyGridAutoFlow, autoFlowValue, important);
3587 addProperty(CSSPropertyGridAutoColumns, autoColumnsValue, important);
3588 addProperty(CSSPropertyGridAutoRows, autoRowsValue, important);
3590 // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
3591 // The sub-properties not specified are set to their initial value, as normal for shorthands.
3592 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createImplicitInitialValue(), important);
3593 addProperty(CSSPropertyGridTemplateRows, cssValuePool().createImplicitInitialValue(), important);
3594 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createImplicitInitialValue(), important);
3599 bool CSSPropertyParser::parseGridAreaShorthand(bool important)
3601 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3603 ShorthandScope scope(this, CSSPropertyGridArea);
3604 const StylePropertyShorthand& shorthand = gridAreaShorthand();
3605 ASSERT_UNUSED(shorthand, shorthand.length() == 4);
3607 RefPtrWillBeRawPtr<CSSValue> rowStartValue = parseGridPosition();
3611 RefPtrWillBeRawPtr<CSSValue> columnStartValue = nullptr;
3612 if (!parseSingleGridAreaLonghand(columnStartValue))
3615 RefPtrWillBeRawPtr<CSSValue> rowEndValue = nullptr;
3616 if (!parseSingleGridAreaLonghand(rowEndValue))
3619 RefPtrWillBeRawPtr<CSSValue> columnEndValue = nullptr;
3620 if (!parseSingleGridAreaLonghand(columnEndValue))
3623 if (!columnStartValue)
3624 columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
3627 rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
3629 if (!columnEndValue)
3630 columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
3632 addProperty(CSSPropertyGridRowStart, rowStartValue, important);
3633 addProperty(CSSPropertyGridColumnStart, columnStartValue, important);
3634 addProperty(CSSPropertyGridRowEnd, rowEndValue, important);
3635 addProperty(CSSPropertyGridColumnEnd, columnEndValue, important);
3639 bool CSSPropertyParser::parseSingleGridAreaLonghand(RefPtrWillBeRawPtr<CSSValue>& property)
3641 if (!m_valueList->current())
3644 if (!isForwardSlashOperator(m_valueList->current()))
3647 if (!m_valueList->next())
3650 property = parseGridPosition();
3654 void CSSPropertyParser::parseGridLineNames(CSSParserValueList& inputList, CSSValueList& valueList, CSSGridLineNamesValue* previousNamedAreaTrailingLineNames)
3656 ASSERT(inputList.current() && inputList.current()->unit == CSSParserValue::ValueList);
3658 CSSParserValueList* identList = inputList.current()->valueList;
3659 if (!identList->size()) {
3664 // Need to ensure the identList is at the heading index, since the parserList might have been rewound.
3665 identList->setCurrentIndex(0);
3667 RefPtrWillBeRawPtr<CSSGridLineNamesValue> lineNames = previousNamedAreaTrailingLineNames;
3669 lineNames = CSSGridLineNamesValue::create();
3670 while (CSSParserValue* identValue = identList->current()) {
3671 ASSERT(identValue->unit == CSSPrimitiveValue::CSS_IDENT);
3672 RefPtrWillBeRawPtr<CSSPrimitiveValue> lineName = createPrimitiveStringValue(identValue);
3673 lineNames->append(lineName.release());
3676 if (!previousNamedAreaTrailingLineNames)
3677 valueList.append(lineNames.release());
3682 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackList(bool important)
3684 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3686 CSSParserValue* value = m_valueList->current();
3687 if (value->id == CSSValueNone) {
3688 m_valueList->next();
3689 return cssValuePool().createIdentifierValue(CSSValueNone);
3692 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
3693 // Handle leading <ident>*.
3694 value = m_valueList->current();
3695 if (value && value->unit == CSSParserValue::ValueList)
3696 parseGridLineNames(*m_valueList, *values);
3698 bool seenTrackSizeOrRepeatFunction = false;
3699 while (CSSParserValue* currentValue = m_valueList->current()) {
3700 if (isForwardSlashOperator(currentValue))
3702 if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "repeat(")) {
3703 if (!parseGridTrackRepeatFunction(*values))
3705 seenTrackSizeOrRepeatFunction = true;
3707 RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
3710 values->append(value);
3711 seenTrackSizeOrRepeatFunction = true;
3713 // This will handle the trailing <ident>* in the grammar.
3714 value = m_valueList->current();
3715 if (value && value->unit == CSSParserValue::ValueList)
3716 parseGridLineNames(*m_valueList, *values);
3719 // We should have found a <track-size> or else it is not a valid <track-list>
3720 if (!seenTrackSizeOrRepeatFunction)
3726 bool CSSPropertyParser::parseGridTrackRepeatFunction(CSSValueList& list)
3728 CSSParserValueList* arguments = m_valueList->current()->function->args.get();
3729 if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1)))
3732 ASSERT_WITH_SECURITY_IMPLICATION(arguments->valueAt(0)->fValue > 0);
3733 size_t repetitions = arguments->valueAt(0)->fValue;
3734 // Clamp repetitions at minRepetitions.
3735 // http://www.w3.org/TR/css-grid-1/#repeat-notation
3736 if (repetitions > minRepetitions)
3737 repetitions = minRepetitions;
3738 RefPtrWillBeRawPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
3739 arguments->next(); // Skip the repetition count.
3740 arguments->next(); // Skip the comma.
3742 // Handle leading <ident>*.
3743 CSSParserValue* currentValue = arguments->current();
3744 if (currentValue && currentValue->unit == CSSParserValue::ValueList)
3745 parseGridLineNames(*arguments, *repeatedValues);
3747 while (arguments->current()) {
3748 RefPtrWillBeRawPtr<CSSValue> trackSize = parseGridTrackSize(*arguments);
3752 repeatedValues->append(trackSize);
3754 // This takes care of any trailing <ident>* in the grammar.
3755 currentValue = arguments->current();
3756 if (currentValue && currentValue->unit == CSSParserValue::ValueList)
3757 parseGridLineNames(*arguments, *repeatedValues);
3760 for (size_t i = 0; i < repetitions; ++i) {
3761 for (size_t j = 0; j < repeatedValues->length(); ++j)
3762 list.append(repeatedValues->itemWithoutBoundsCheck(j));
3765 // parseGridTrackSize iterated over the repeat arguments, move to the next value.
3766 m_valueList->next();
3771 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackSize(CSSParserValueList& inputList)
3773 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3775 CSSParserValue* currentValue = inputList.current();
3778 if (currentValue->id == CSSValueAuto)
3779 return cssValuePool().createIdentifierValue(CSSValueAuto);
3781 if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax(")) {
3782 // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
3783 CSSParserValueList* arguments = currentValue->function->args.get();
3784 if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
3787 RefPtrWillBeRawPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0));
3788 if (!minTrackBreadth)
3791 RefPtrWillBeRawPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2));
3792 if (!maxTrackBreadth)
3795 RefPtrWillBeRawPtr<CSSValueList> parsedArguments = CSSValueList::createCommaSeparated();
3796 parsedArguments->append(minTrackBreadth);
3797 parsedArguments->append(maxTrackBreadth);
3798 return CSSFunctionValue::create("minmax(", parsedArguments);
3801 return parseGridBreadth(currentValue);
3804 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseGridBreadth(CSSParserValue* currentValue)
3806 if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMaxContent)
3807 return cssValuePool().createIdentifierValue(currentValue->id);
3809 if (currentValue->unit == CSSPrimitiveValue::CSS_FR) {
3810 double flexValue = currentValue->fValue;
3812 // Fractional unit is a non-negative dimension.
3816 return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR);
3819 if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
3822 return createPrimitiveNumericValue(currentValue);
3825 bool CSSPropertyParser::parseGridTemplateAreasRow(NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount)
3827 CSSParserValue* currentValue = m_valueList->current();
3828 if (!currentValue || currentValue->unit != CSSPrimitiveValue::CSS_STRING)
3831 String gridRowNames = currentValue->string;
3832 if (!gridRowNames.length())
3835 Vector<String> columnNames;
3836 gridRowNames.split(' ', columnNames);
3839 columnCount = columnNames.size();
3840 ASSERT(columnCount);
3841 } else if (columnCount != columnNames.size()) {
3842 // The declaration is invalid is all the rows don't have the number of columns.
3846 for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
3847 const String& gridAreaName = columnNames[currentCol];
3849 // Unamed areas are always valid (we consider them to be 1x1).
3850 if (gridAreaName == ".")
3853 // We handle several grid areas with the same name at once to simplify the validation code.
3854 size_t lookAheadCol;
3855 for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++lookAheadCol) {
3856 if (columnNames[lookAheadCol + 1] != gridAreaName)
3860 NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
3861 if (gridAreaIt == gridAreaMap.end()) {
3862 gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowCount), GridSpan(currentCol, lookAheadCol)));
3864 GridCoordinate& gridCoordinate = gridAreaIt->value;
3866 // The following checks test that the grid area is a single filled-in rectangle.
3867 // 1. The new row is adjacent to the previously parsed row.
3868 if (rowCount != gridCoordinate.rows.resolvedFinalPosition.next().toInt())
3871 // 2. The new area starts at the same position as the previously parsed area.
3872 if (currentCol != gridCoordinate.columns.resolvedInitialPosition.toInt())
3875 // 3. The new area ends at the same position as the previously parsed area.
3876 if (lookAheadCol != gridCoordinate.columns.resolvedFinalPosition.toInt())
3879 ++gridCoordinate.rows.resolvedFinalPosition;
3881 currentCol = lookAheadCol;
3884 m_valueList->next();
3888 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTemplateAreas()
3890 NamedGridAreaMap gridAreaMap;
3891 size_t rowCount = 0;
3892 size_t columnCount = 0;
3894 while (m_valueList->current()) {
3895 if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
3900 if (!rowCount || !columnCount)
3903 return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
3906 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseCounterContent(CSSParserValueList* args, bool counters)
3908 unsigned numArgs = args->size();
3909 if (counters && numArgs != 3 && numArgs != 5)
3911 if (!counters && numArgs != 1 && numArgs != 3)
3914 CSSParserValue* i = args->current();
3915 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
3917 RefPtrWillBeRawPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i);
3919 RefPtrWillBeRawPtr<CSSPrimitiveValue> separator = nullptr;
3921 separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING);
3924 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
3928 if (i->unit != CSSPrimitiveValue::CSS_STRING)
3931 separator = createPrimitiveStringValue(i);
3934 RefPtrWillBeRawPtr<CSSPrimitiveValue> listStyle = nullptr;
3936 if (!i) // Make the list style default decimal
3937 listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
3939 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
3943 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
3946 CSSValueID listStyleID = CSSValueInvalid;
3947 if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha))
3948 listStyleID = i->id;
3952 listStyle = cssValuePool().createIdentifierValue(listStyleID);
3955 return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
3958 bool CSSPropertyParser::parseClipShape(CSSPropertyID propId, bool important)
3960 CSSParserValue* value = m_valueList->current();
3961 CSSParserValueList* args = value->function->args.get();
3963 if (!equalIgnoringCase(value->function->name, "rect(") || !args)
3966 // rect(t, r, b, l) || rect(t r b l)
3967 if (args->size() != 4 && args->size() != 7)
3969 RefPtrWillBeRawPtr<Rect> rect = Rect::create();
3972 CSSParserValue* a = args->current();
3974 valid = a->id == CSSValueAuto || validUnit(a, FLength);
3977 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
3978 cssValuePool().createIdentifierValue(CSSValueAuto) :
3979 createPrimitiveNumericValue(a);
3981 rect->setTop(length);
3983 rect->setRight(length);
3985 rect->setBottom(length);
3987 rect->setLeft(length);
3989 if (a && args->size() == 7) {
3990 if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
4000 addProperty(propId, cssValuePool().createValue(rect.release()), important);
4001 m_valueList->next();
4007 static void completeBorderRadii(RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[4])
4013 radii[1] = radii[0];
4014 radii[2] = radii[0];
4016 radii[3] = radii[1];
4019 // FIXME: This should be refactored with CSSParser::parseBorderRadius.
4020 // CSSParser::parseBorderRadius contains support for some legacy radius construction.
4021 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseInsetRoundedCorners(PassRefPtrWillBeRawPtr<CSSBasicShapeInset> shape, CSSParserValueList* args)
4023 CSSParserValue* argument = args->next();
4028 Vector<CSSParserValue*> radiusArguments;
4030 radiusArguments.append(argument);
4031 argument = args->next();
4034 unsigned num = radiusArguments.size();
4035 if (!num || num > 9)
4038 // FIXME: Refactor completeBorderRadii and the array
4039 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
4041 // Zero initialize the array of raw pointers.
4042 memset(&radii, 0, sizeof(radii));
4045 unsigned indexAfterSlash = 0;
4046 for (unsigned i = 0; i < num; ++i) {
4047 CSSParserValue* value = radiusArguments.at(i);
4048 if (value->unit == CSSParserValue::Operator) {
4049 if (value->iValue != '/')
4052 if (!i || indexAfterSlash || i + 1 == num)
4055 indexAfterSlash = i + 1;
4056 completeBorderRadii(radii[0]);
4060 if (i - indexAfterSlash >= 4)
4063 if (!validUnit(value, FLength | FPercent | FNonNeg))
4066 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
4068 if (!indexAfterSlash)
4069 radii[0][i] = radius;
4071 radii[1][i - indexAfterSlash] = radius.release();
4074 if (!indexAfterSlash) {
4075 completeBorderRadii(radii[0]);
4076 for (unsigned i = 0; i < 4; ++i)
4077 radii[1][i] = radii[0][i];
4079 completeBorderRadii(radii[1]);
4081 shape->setTopLeftRadius(createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()));
4082 shape->setTopRightRadius(createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()));
4083 shape->setBottomRightRadius(createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()));
4084 shape->setBottomLeftRadius(createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()));
4089 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeInset(CSSParserValueList* args)
4093 RefPtrWillBeRawPtr<CSSBasicShapeInset> shape = CSSBasicShapeInset::create();
4095 CSSParserValue* argument = args->current();
4096 WillBeHeapVector<RefPtrWillBeMember<CSSPrimitiveValue> > widthArguments;
4097 bool hasRoundedInset = false;
4100 if (argument->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(argument->string, "round")) {
4101 hasRoundedInset = true;
4105 Units unitFlags = FLength | FPercent;
4106 if (!validUnit(argument, unitFlags) || widthArguments.size() > 4)
4109 widthArguments.append(createPrimitiveNumericValue(argument));
4110 argument = args->next();
4113 switch (widthArguments.size()) {
4115 shape->updateShapeSize1Value(widthArguments[0].get());
4119 shape->updateShapeSize2Values(widthArguments[0].get(), widthArguments[1].get());
4123 shape->updateShapeSize3Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get());
4127 shape->updateShapeSize4Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get(), widthArguments[3].get());
4134 if (hasRoundedInset)
4135 return parseInsetRoundedCorners(shape, args);
4139 static bool isItemPositionKeyword(CSSValueID id)
4141 return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
4142 || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
4143 || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight;
4146 bool CSSPropertyParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important)
4148 // auto | baseline | stretch | [<item-position> && <overflow-position>? ]
4149 // <item-position> = center | start | end | self-start | self-end | flex-start | flex-end | left | right;
4150 // <overflow-position> = true | safe
4152 CSSParserValue* value = m_valueList->current();
4154 if (value->id == CSSValueAuto || value->id == CSSValueBaseline || value->id == CSSValueStretch) {
4155 if (m_valueList->next())
4158 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
4162 RefPtrWillBeRawPtr<CSSPrimitiveValue> position = nullptr;
4163 RefPtrWillBeRawPtr<CSSPrimitiveValue> overflowAlignmentKeyword = nullptr;
4164 if (isItemPositionKeyword(value->id)) {
4165 position = cssValuePool().createIdentifierValue(value->id);
4166 value = m_valueList->next();
4168 if (value->id == CSSValueTrue || value->id == CSSValueSafe)
4169 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
4173 } else if (value->id == CSSValueTrue || value->id == CSSValueSafe) {
4174 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
4175 value = m_valueList->next();
4176 if (value && isItemPositionKeyword(value->id))
4177 position = cssValuePool().createIdentifierValue(value->id);
4184 if (m_valueList->next())
4188 if (overflowAlignmentKeyword)
4189 addProperty(propId, createPrimitiveValuePair(position, overflowAlignmentKeyword), important);
4191 addProperty(propId, position.release(), important);
4196 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseShapeRadius(CSSParserValue* value)
4198 if (value->id == CSSValueClosestSide || value->id == CSSValueFarthestSide)
4199 return cssValuePool().createIdentifierValue(value->id);
4201 if (!validUnit(value, FLength | FPercent | FNonNeg))
4204 return createPrimitiveNumericValue(value);
4207 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeCircle(CSSParserValueList* args)
4212 // circle(radius at <position>)
4213 // circle(at <position>)
4214 // where position defines centerX and centerY using a CSS <position> data type.
4215 RefPtrWillBeRawPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
4217 for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
4218 // The call to parseFillPosition below should consume all of the
4219 // arguments except the first two. Thus, and index greater than one
4220 // indicates an invalid production.
4221 if (args->currentIndex() > 1)
4224 if (!args->currentIndex() && argument->id != CSSValueAt) {
4225 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
4226 shape->setRadius(radius);
4233 if (argument->id == CSSValueAt && args->next()) {
4234 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
4235 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
4236 parseFillPosition(args, centerX, centerY);
4237 if (centerX && centerY && !args->current()) {
4238 ASSERT(centerX->isPrimitiveValue());
4239 ASSERT(centerY->isPrimitiveValue());
4240 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
4241 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
4253 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeEllipse(CSSParserValueList* args)
4258 // ellipse(radiusX at <position>)
4259 // ellipse(radiusX radiusY)
4260 // ellipse(radiusX radiusY at <position>)
4261 // ellipse(at <position>)
4262 // where position defines centerX and centerY using a CSS <position> data type.
4263 RefPtrWillBeRawPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
4265 for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
4266 // The call to parseFillPosition below should consume all of the
4267 // arguments except the first three. Thus, an index greater than two
4268 // indicates an invalid production.
4269 if (args->currentIndex() > 2)
4272 if (args->currentIndex() < 2 && argument->id != CSSValueAt) {
4273 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
4274 if (!shape->radiusX())
4275 shape->setRadiusX(radius);
4277 shape->setRadiusY(radius);
4284 if (argument->id != CSSValueAt || !args->next()) // expecting ellipse(.. at <position>)
4286 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
4287 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
4288 parseFillPosition(args, centerX, centerY);
4289 if (!centerX || !centerY || args->current())
4292 ASSERT(centerX->isPrimitiveValue());
4293 ASSERT(centerY->isPrimitiveValue());
4294 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
4295 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
4301 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapePolygon(CSSParserValueList* args)
4305 unsigned size = args->size();
4309 RefPtrWillBeRawPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
4311 CSSParserValue* argument = args->current();
4312 if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
4313 shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
4315 if (!isComma(args->next()))
4318 argument = args->next();
4322 // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one
4323 if (!size || (size % 3) - 2)
4326 CSSParserValue* argumentX = argument;
4329 if (!validUnit(argumentX, FLength | FPercent))
4331 RefPtrWillBeRawPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX);
4333 CSSParserValue* argumentY = args->next();
4334 if (!argumentY || !validUnit(argumentY, FLength | FPercent))
4337 RefPtrWillBeRawPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY);
4339 shape->appendPoint(xLength.release(), yLength.release());
4341 CSSParserValue* commaOrNull = args->next();
4344 else if (!isComma(commaOrNull))
4347 argumentX = args->next();
4353 static bool isBoxValue(CSSValueID valueId)
4356 case CSSValueContentBox:
4357 case CSSValuePaddingBox:
4358 case CSSValueBorderBox:
4359 case CSSValueMarginBox:
4368 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseShapeProperty(CSSPropertyID propId)
4370 if (!RuntimeEnabledFeatures::cssShapesEnabled())
4373 CSSParserValue* value = m_valueList->current();
4374 CSSValueID valueId = value->id;
4376 if (valueId == CSSValueNone) {
4377 RefPtrWillBeRawPtr<CSSPrimitiveValue> keywordValue = parseValidPrimitive(valueId, value);
4378 m_valueList->next();
4379 return keywordValue.release();
4382 RefPtrWillBeRawPtr<CSSValue> imageValue = nullptr;
4383 if (valueId != CSSValueNone && parseFillImage(m_valueList.get(), imageValue)) {
4384 m_valueList->next();
4385 return imageValue.release();
4388 return parseBasicShapeAndOrBox();
4391 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBasicShapeAndOrBox()
4393 CSSParserValue* value = m_valueList->current();
4395 bool shapeFound = false;
4396 bool boxFound = false;
4399 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
4400 for (unsigned i = 0; i < 2; ++i) {
4403 valueId = value->id;
4404 if (value->unit == CSSParserValue::Function && !shapeFound) {
4405 // parseBasicShape already asks for the next value list item.
4406 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = parseBasicShape();
4409 list->append(shapeValue.release());
4411 } else if (isBoxValue(valueId) && !boxFound) {
4412 list->append(parseValidPrimitive(valueId, value));
4414 m_valueList->next();
4419 value = m_valueList->current();
4422 if (m_valueList->current())
4424 return list.release();
4427 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseBasicShape()
4429 CSSParserValue* value = m_valueList->current();
4430 ASSERT(value->unit == CSSParserValue::Function);
4431 CSSParserValueList* args = value->function->args.get();
4436 RefPtrWillBeRawPtr<CSSBasicShape> shape = nullptr;
4437 if (equalIgnoringCase(value->function->name, "circle("))
4438 shape = parseBasicShapeCircle(args);
4439 else if (equalIgnoringCase(value->function->name, "ellipse("))
4440 shape = parseBasicShapeEllipse(args);
4441 else if (equalIgnoringCase(value->function->name, "polygon("))
4442 shape = parseBasicShapePolygon(args);
4443 else if (equalIgnoringCase(value->function->name, "inset("))
4444 shape = parseBasicShapeInset(args);
4449 m_valueList->next();
4451 return cssValuePool().createValue(shape.release());
4454 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
4455 bool CSSPropertyParser::parseFont(bool important)
4457 // Let's check if there is an inherit or initial somewhere in the shorthand.
4458 for (unsigned i = 0; i < m_valueList->size(); ++i) {
4459 if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial)
4463 ShorthandScope scope(this, CSSPropertyFont);
4464 // Optional font-style, font-variant and font-weight.
4465 bool fontStyleParsed = false;
4466 bool fontVariantParsed = false;
4467 bool fontWeightParsed = false;
4468 CSSParserValue* value;
4469 while ((value = m_valueList->current())) {
4470 if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
4471 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
4472 fontStyleParsed = true;
4473 } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
4474 // Font variant in the shorthand is particular, it only accepts normal or small-caps.
4475 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important);
4476 fontVariantParsed = true;
4477 } else if (!fontWeightParsed && parseFontWeight(important))
4478 fontWeightParsed = true;
4481 m_valueList->next();
4487 if (!fontStyleParsed)
4488 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4489 if (!fontVariantParsed)
4490 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4491 if (!fontWeightParsed)
4492 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4494 // Now a font size _must_ come.
4495 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
4496 if (!parseFontSize(important))
4499 value = m_valueList->current();
4503 if (isForwardSlashOperator(value)) {
4504 // The line-height property.
4505 value = m_valueList->next();
4508 if (!parseLineHeight(important))
4511 addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4513 // Font family must come now.
4514 RefPtrWillBeRawPtr<CSSValue> parsedFamilyValue = parseFontFamily();
4515 if (!parsedFamilyValue)
4518 addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
4520 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
4521 // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
4522 // but we don't seem to support them at the moment. They should also be added here once implemented.
4523 if (m_valueList->current())
4529 class FontFamilyValueBuilder {
4530 DISALLOW_ALLOCATION();
4532 FontFamilyValueBuilder(CSSValueList* list)
4537 void add(const CSSParserString& string)
4539 if (!m_builder.isEmpty())
4540 m_builder.append(' ');
4542 if (string.is8Bit()) {
4543 m_builder.append(string.characters8(), string.length());
4547 m_builder.append(string.characters16(), string.length());
4552 if (m_builder.isEmpty())
4554 m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString()));
4559 StringBuilder m_builder;
4560 CSSValueList* m_list;
4563 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFontFamily()
4565 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
4566 CSSParserValue* value = m_valueList->current();
4568 FontFamilyValueBuilder familyBuilder(list.get());
4569 bool inFamily = false;
4572 CSSParserValue* nextValue = m_valueList->next();
4573 bool nextValBreaksFont = !nextValue ||
4574 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
4575 bool nextValIsFontName = nextValue &&
4576 ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
4577 (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
4579 if (isCSSWideKeyword(*value) && !inFamily) {
4580 if (nextValBreaksFont)
4581 value = m_valueList->next();
4582 else if (nextValIsFontName)
4587 if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
4589 familyBuilder.add(value->string);
4590 else if (nextValBreaksFont || !nextValIsFontName)
4591 list->append(cssValuePool().createIdentifierValue(value->id));
4593 familyBuilder.commit();
4594 familyBuilder.add(value->string);
4597 } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
4598 // Strings never share in a family name.
4600 familyBuilder.commit();
4601 list->append(cssValuePool().createFontFamilyValue(value->string));
4602 } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
4604 familyBuilder.add(value->string);
4605 else if (nextValBreaksFont || !nextValIsFontName)
4606 list->append(cssValuePool().createFontFamilyValue(value->string));
4608 familyBuilder.commit();
4609 familyBuilder.add(value->string);
4619 if (nextValBreaksFont) {
4620 value = m_valueList->next();
4621 familyBuilder.commit();
4624 else if (nextValIsFontName)
4629 familyBuilder.commit();
4631 if (!list->length())
4633 return list.release();
4636 bool CSSPropertyParser::parseLineHeight(bool important)
4638 CSSParserValue* value = m_valueList->current();
4639 CSSValueID id = value->id;
4640 bool validPrimitive = false;
4641 // normal | <number> | <length> | <percentage> | inherit
4642 if (id == CSSValueNormal)
4643 validPrimitive = true;
4645 validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
4646 if (validPrimitive && (!m_valueList->next() || inShorthand()))
4647 addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important);
4648 return validPrimitive;
4651 bool CSSPropertyParser::parseFontSize(bool important)
4653 CSSParserValue* value = m_valueList->current();
4654 CSSValueID id = value->id;
4655 bool validPrimitive = false;
4656 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
4657 if (id >= CSSValueXxSmall && id <= CSSValueLarger)
4658 validPrimitive = true;
4660 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
4661 if (validPrimitive && (!m_valueList->next() || inShorthand()))
4662 addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important);
4663 return validPrimitive;
4666 bool CSSPropertyParser::parseFontVariant(bool important)
4668 RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
4669 if (m_valueList->size() > 1)
4670 values = CSSValueList::createCommaSeparated();
4671 CSSParserValue* val;
4672 bool expectComma = false;
4673 while ((val = m_valueList->current())) {
4674 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue = nullptr;
4677 if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
4678 parsedValue = cssValuePool().createIdentifierValue(val->id);
4679 else if (val->id == CSSValueAll && !values) {
4680 // FIXME: CSSPropertyParser::parseFontVariant() implements
4681 // the old css3 draft:
4682 // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#font-variant
4683 // 'all' is only allowed in @font-face and with no other values. Make a value list to
4684 // indicate that we are in the @font-face case.
4685 values = CSSValueList::createCommaSeparated();
4686 parsedValue = cssValuePool().createIdentifierValue(val->id);
4688 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
4689 expectComma = false;
4690 m_valueList->next();
4697 m_valueList->next();
4700 values->append(parsedValue.release());
4702 addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
4707 if (values && values->length()) {
4708 if (m_ruleType != CSSRuleSourceData::FONT_FACE_RULE)
4710 addProperty(CSSPropertyFontVariant, values.release(), important);
4717 bool CSSPropertyParser::parseFontWeight(bool important)
4719 CSSParserValue* value = m_valueList->current();
4720 if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
4721 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important);
4724 if (validUnit(value, FInteger | FNonNeg, HTMLQuirksMode)) {
4725 int weight = static_cast<int>(value->fValue);
4726 if (!(weight % 100) && weight >= 100 && weight <= 900) {
4727 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1)), important);
4734 bool CSSPropertyParser::parseFontFaceSrcURI(CSSValueList* valueList)
4736 RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string)));
4737 uriValue->setReferrer(m_context.referrer());
4739 CSSParserValue* value = m_valueList->next();
4741 valueList->append(uriValue.release());
4744 if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
4745 m_valueList->next();
4746 valueList->append(uriValue.release());
4750 if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format("))
4753 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
4754 // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
4755 CSSParserValueList* args = value->function->args.get();
4756 if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
4758 uriValue->setFormat(args->current()->string);
4759 valueList->append(uriValue.release());
4760 value = m_valueList->next();
4761 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
4762 m_valueList->next();
4766 bool CSSPropertyParser::parseFontFaceSrcLocal(CSSValueList* valueList)
4768 CSSParserValueList* args = m_valueList->current()->function->args.get();
4769 if (!args || !args->size())
4772 if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING)
4773 valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string));
4774 else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
4775 StringBuilder builder;
4776 for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) {
4777 if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
4779 if (!builder.isEmpty())
4780 builder.append(' ');
4781 builder.append(localValue->string);
4783 valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
4787 if (CSSParserValue* value = m_valueList->next()) {
4788 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
4789 m_valueList->next();
4794 bool CSSPropertyParser::parseFontFaceSrc()
4796 RefPtrWillBeRawPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
4798 while (CSSParserValue* value = m_valueList->current()) {
4799 if (value->unit == CSSPrimitiveValue::CSS_URI) {
4800 if (!parseFontFaceSrcURI(values.get()))
4802 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) {
4803 if (!parseFontFaceSrcLocal(values.get()))
4808 if (!values->length())
4811 addProperty(CSSPropertySrc, values.release(), m_important);
4812 m_valueList->next();
4816 bool CSSPropertyParser::parseFontFaceUnicodeRange()
4818 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
4819 bool failed = false;
4820 bool operatorExpected = false;
4821 for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
4822 if (operatorExpected) {
4823 if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
4828 if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
4833 String rangeString = m_valueList->current()->string;
4836 unsigned length = rangeString.length();
4844 while (i < length) {
4845 UChar c = rangeString[i];
4846 if (c == '-' || c == '?')
4849 if (c >= '0' && c <= '9')
4851 else if (c >= 'A' && c <= 'F')
4852 from += 10 + c - 'A';
4853 else if (c >= 'a' && c <= 'f')
4854 from += 10 + c - 'a';
4866 else if (rangeString[i] == '?') {
4868 while (i < length && rangeString[i] == '?') {
4875 to = from + span - 1;
4877 if (length < i + 2) {
4882 while (i < length) {
4883 UChar c = rangeString[i];
4885 if (c >= '0' && c <= '9')
4887 else if (c >= 'A' && c <= 'F')
4889 else if (c >= 'a' && c <= 'f')
4901 values->append(CSSUnicodeRangeValue::create(from, to));
4903 if (failed || !values->length())
4905 addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
4909 // Returns the number of characters which form a valid double
4910 // and are terminated by the given terminator character
4911 template <typename CharacterType>
4912 static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
4914 int length = end - string;
4918 bool decimalMarkSeen = false;
4919 int processedLength = 0;
4921 for (int i = 0; i < length; ++i) {
4922 if (string[i] == terminator) {
4923 processedLength = i;
4926 if (!isASCIIDigit(string[i])) {
4927 if (!decimalMarkSeen && string[i] == '.')
4928 decimalMarkSeen = true;
4934 if (decimalMarkSeen && processedLength == 1)
4937 return processedLength;
4940 // Returns the number of characters consumed for parsing a valid double
4941 // terminated by the given terminator character
4942 template <typename CharacterType>
4943 static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value)
4945 int length = checkForValidDouble(string, end, terminator);
4950 double localValue = 0;
4952 // The consumed characters here are guaranteed to be
4953 // ASCII digits with or without a decimal mark
4954 for (; position < length; ++position) {
4955 if (string[position] == '.')
4957 localValue = localValue * 10 + string[position] - '0';
4960 if (++position == length) {
4965 double fraction = 0;
4968 while (position < length && scale < MAX_SCALE) {
4969 fraction = fraction * 10 + string[position++] - '0';
4973 value = localValue + fraction / scale;
4977 template <typename CharacterType>
4978 static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitType& expect, int& value)
4980 const CharacterType* current = string;
4981 double localValue = 0;
4982 bool negative = false;
4983 while (current != end && isHTMLSpace<CharacterType>(*current))
4985 if (current != end && *current == '-') {
4989 if (current == end || !isASCIIDigit(*current))
4991 while (current != end && isASCIIDigit(*current)) {
4992 double newValue = localValue * 10 + *current++ - '0';
4993 if (newValue >= 255) {
4994 // Clamp values at 255.
4996 while (current != end && isASCIIDigit(*current))
5000 localValue = newValue;
5006 if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
5009 if (*current == '.') {
5010 // We already parsed the integral part, try to parse
5011 // the fraction part of the percentage value.
5012 double percentage = 0;
5013 int numCharactersParsed = parseDouble(current, end, '%', percentage);
5014 if (!numCharactersParsed)
5016 current += numCharactersParsed;
5017 if (*current != '%')
5019 localValue += percentage;
5022 if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
5025 if (*current == '%') {
5026 expect = CSSPrimitiveValue::CSS_PERCENTAGE;
5027 localValue = localValue / 100.0 * 256.0;
5028 // Clamp values at 255 for percentages over 100%
5029 if (localValue > 255)
5033 expect = CSSPrimitiveValue::CSS_NUMBER;
5035 while (current != end && isHTMLSpace<CharacterType>(*current))
5037 if (current == end || *current++ != terminator)
5039 // Clamp negative values at zero.
5040 value = negative ? 0 : static_cast<int>(localValue);
5045 template <typename CharacterType>
5046 static inline bool isTenthAlpha(const CharacterType* string, const int length)
5049 if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
5053 if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
5059 template <typename CharacterType>
5060 static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
5062 while (string != end && isHTMLSpace<CharacterType>(*string))
5065 bool negative = false;
5067 if (string != end && *string == '-') {
5074 int length = end - string;
5078 if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
5081 if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
5082 if (checkForValidDouble(string, end, terminator)) {
5083 value = negative ? 0 : 255;
5090 if (length == 2 && string[0] != '.') {
5091 value = !negative && string[0] == '1' ? 255 : 0;
5096 if (isTenthAlpha(string, length - 1)) {
5097 static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
5098 value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
5104 if (!parseDouble(string, end, terminator, alpha))
5106 value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
5111 template <typename CharacterType>
5112 static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
5116 return characters[4] == '('
5117 && isASCIIAlphaCaselessEqual(characters[0], 'r')
5118 && isASCIIAlphaCaselessEqual(characters[1], 'g')
5119 && isASCIIAlphaCaselessEqual(characters[2], 'b')
5120 && isASCIIAlphaCaselessEqual(characters[3], 'a');
5123 template <typename CharacterType>
5124 static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
5128 return characters[3] == '('
5129 && isASCIIAlphaCaselessEqual(characters[0], 'r')
5130 && isASCIIAlphaCaselessEqual(characters[1], 'g')
5131 && isASCIIAlphaCaselessEqual(characters[2], 'b');
5134 template <typename CharacterType>
5135 static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length , bool strict)
5137 CSSPrimitiveValue::UnitType expect = CSSPrimitiveValue::CSS_UNKNOWN;
5139 if (length >= 4 && characters[0] == '#')
5140 return Color::parseHexColor(characters + 1, length - 1, rgb);
5142 if (!strict && length >= 3) {
5143 if (Color::parseHexColor(characters, length, rgb))
5147 // Try rgba() syntax.
5148 if (mightBeRGBA(characters, length)) {
5149 const CharacterType* current = characters + 5;
5150 const CharacterType* end = characters + length;
5156 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
5158 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
5160 if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
5162 if (!parseAlphaValue(current, end, ')', alpha))
5166 rgb = makeRGBA(red, green, blue, alpha);
5170 // Try rgb() syntax.
5171 if (mightBeRGB(characters, length)) {
5172 const CharacterType* current = characters + 4;
5173 const CharacterType* end = characters + length;
5177 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
5179 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
5181 if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
5185 rgb = makeRGB(red, green, blue);
5192 template<typename StringType>
5193 bool CSSPropertyParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict)
5195 unsigned length = name.length();
5202 parseResult = fastParseColorInternal(rgb, name.characters8(), length, strict);
5204 parseResult = fastParseColorInternal(rgb, name.characters16(), length, strict);
5209 // Try named colors.
5211 if (!tc.setNamedColor(name))
5217 template bool CSSPropertyParser::fastParseColor(RGBA32&, const String&, bool strict);
5219 inline double CSSPropertyParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc)
5221 const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue;
5222 if (releaseCalc == ReleaseParsedCalcValue)
5223 m_parsedCalculation.release();
5227 bool CSSPropertyParser::isCalculation(CSSParserValue* value)
5229 return (value->unit == CSSParserValue::Function)
5230 && (equalIgnoringCase(value->function->name, "calc(")
5231 || equalIgnoringCase(value->function->name, "-webkit-calc(")
5232 || equalIgnoringCase(value->function->name, "-webkit-min(")
5233 || equalIgnoringCase(value->function->name, "-webkit-max("));
5236 inline int CSSPropertyParser::colorIntFromValue(CSSParserValue* v)
5240 if (m_parsedCalculation)
5241 isPercent = m_parsedCalculation->category() == CalcPercent;
5243 isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
5245 const double value = parsedDouble(v, ReleaseParsedCalcValue);
5253 return static_cast<int>(value * 256.0 / 100.0);
5259 return static_cast<int>(value);
5262 bool CSSPropertyParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
5264 CSSParserValueList* args = value->function->args.get();
5265 CSSParserValue* v = args->current();
5266 Units unitType = FUnknown;
5267 // Get the first value and its type
5268 if (validUnit(v, FInteger, HTMLStandardMode))
5269 unitType = FInteger;
5270 else if (validUnit(v, FPercent, HTMLStandardMode))
5271 unitType = FPercent;
5275 colorArray[0] = colorIntFromValue(v);
5276 for (int i = 1; i < 3; i++) {
5278 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5281 if (!validUnit(v, unitType, HTMLStandardMode))
5283 colorArray[i] = colorIntFromValue(v);
5287 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5290 if (!validUnit(v, FNumber, HTMLStandardMode))
5292 const double value = parsedDouble(v, ReleaseParsedCalcValue);
5293 // Convert the floating pointer number of alpha to an integer in the range [0, 256),
5294 // with an equal distribution across all 256 values.
5295 colorArray[3] = static_cast<int>(std::max(0.0, std::min(1.0, value)) * nextafter(256.0, 0.0));
5300 // The CSS3 specification defines the format of a HSL color as
5301 // hsl(<number>, <percent>, <percent>)
5302 // and with alpha, the format is
5303 // hsla(<number>, <percent>, <percent>, <number>)
5304 // The first value, HUE, is in an angle with a value between 0 and 360
5305 bool CSSPropertyParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
5307 CSSParserValueList* args = value->function->args.get();
5308 CSSParserValue* v = args->current();
5309 // Get the first value
5310 if (!validUnit(v, FNumber, HTMLStandardMode))
5312 // normalize the Hue value and change it to be between 0 and 1.0
5313 colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0;
5314 for (int i = 1; i < 3; i++) {
5316 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5319 if (!validUnit(v, FPercent, HTMLStandardMode))
5321 colorArray[i] = std::max(0.0, std::min(100.0, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0
5325 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5328 if (!validUnit(v, FNumber, HTMLStandardMode))
5330 colorArray[3] = std::max(0.0, std::min(1.0, parsedDouble(v, ReleaseParsedCalcValue)));
5335 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseColor(CSSParserValue* value)
5337 RGBA32 c = Color::transparent;
5338 if (!parseColorFromValue(value ? value : m_valueList->current(), c))
5340 return cssValuePool().createColorValue(c);
5343 bool CSSPropertyParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
5345 if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
5346 && value->fValue >= 0. && value->fValue < 1000000.) {
5347 String str = String::format("%06d", static_cast<int>((value->fValue+.5)));
5348 // FIXME: This should be strict parsing for SVG as well.
5349 if (!fastParseColor(c, str, !inQuirksMode()))
5351 } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
5352 value->unit == CSSPrimitiveValue::CSS_IDENT ||
5353 (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
5354 if (!fastParseColor(c, value->string, !inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
5356 } else if (value->unit == CSSParserValue::Function &&
5357 value->function->args != 0 &&
5358 value->function->args->size() == 5 /* rgb + two commas */ &&
5359 equalIgnoringCase(value->function->name, "rgb(")) {
5361 if (!parseColorParameters(value, colorValues, false))
5363 c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
5365 if (value->unit == CSSParserValue::Function &&
5366 value->function->args != 0 &&
5367 value->function->args->size() == 7 /* rgba + three commas */ &&
5368 equalIgnoringCase(value->function->name, "rgba(")) {
5370 if (!parseColorParameters(value, colorValues, true))
5372 c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
5373 } else if (value->unit == CSSParserValue::Function &&
5374 value->function->args != 0 &&
5375 value->function->args->size() == 5 /* hsl + two commas */ &&
5376 equalIgnoringCase(value->function->name, "hsl(")) {
5377 double colorValues[3];
5378 if (!parseHSLParameters(value, colorValues, false))
5380 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
5381 } else if (value->unit == CSSParserValue::Function &&
5382 value->function->args != 0 &&
5383 value->function->args->size() == 7 /* hsla + three commas */ &&
5384 equalIgnoringCase(value->function->name, "hsla(")) {
5385 double colorValues[4];
5386 if (!parseHSLParameters(value, colorValues, true))
5388 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
5396 // This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return)
5397 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
5398 class ShadowParseContext {
5401 ShadowParseContext(CSSPropertyID prop, CSSPropertyParser* parser)
5407 , allowSpread(false)
5409 , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
5414 bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
5418 // Handle the ,, case gracefully by doing nothing.
5419 if (x || y || blur || spread || color || style) {
5421 values = CSSValueList::createCommaSeparated();
5423 // Construct the current shadow value and add it to the list.
5424 values->append(CSSShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
5427 // Now reset for the next shadow value.
5440 allowSpread = false;
5441 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5444 void commitLength(CSSParserValue* v)
5446 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
5455 } else if (allowY) {
5460 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5462 } else if (allowBlur) {
5463 blur = val.release();
5465 allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5466 } else if (allowSpread) {
5467 spread = val.release();
5468 allowSpread = false;
5472 void commitColor(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val)
5481 allowSpread = false;
5482 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5486 void commitStyle(CSSParserValue* v)
5488 style = cssValuePool().createIdentifierValue(v->id);
5494 allowSpread = false;
5499 CSSPropertyID property;
5500 CSSPropertyParser* m_parser;
5502 RefPtrWillBeMember<CSSValueList> values;
5503 RefPtrWillBeMember<CSSPrimitiveValue> x;
5504 RefPtrWillBeMember<CSSPrimitiveValue> y;
5505 RefPtrWillBeMember<CSSPrimitiveValue> blur;
5506 RefPtrWillBeMember<CSSPrimitiveValue> spread;
5507 RefPtrWillBeMember<CSSPrimitiveValue> style;
5508 RefPtrWillBeMember<CSSPrimitiveValue> color;
5515 bool allowStyle; // inset or not.
5519 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId)
5521 ShadowParseContext context(propId, this);
5522 CSSParserValue* val;
5523 while ((val = valueList->current())) {
5524 // Check for a comma break first.
5525 if (val->unit == CSSParserValue::Operator) {
5526 if (val->iValue != ',' || !context.allowBreak) {
5527 // Other operators aren't legal or we aren't done with the current shadow
5528 // value. Treat as invalid.
5531 // The value is good. Commit it.
5532 context.commitValue();
5533 } else if (validUnit(val, FLength, HTMLStandardMode)) {
5534 // We required a length and didn't get one. Invalid.
5535 if (!context.allowLength())
5538 // Blur radius must be non-negative.
5539 if (context.allowBlur && !validUnit(val, FLength | FNonNeg, HTMLStandardMode))
5542 // A length is allowed here. Construct the value and add it.
5543 context.commitLength(val);
5544 } else if (val->id == CSSValueInset) {
5545 if (!context.allowStyle)
5548 context.commitStyle(val);
5550 // The only other type of value that's ok is a color value.
5551 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedColor = nullptr;
5552 bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu
5553 || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode())
5554 || val->id == CSSValueCurrentcolor);
5556 if (!context.allowColor)
5558 parsedColor = cssValuePool().createIdentifierValue(val->id);
5562 // It's not built-in. Try to parse it as a color.
5563 parsedColor = parseColor(val);
5565 if (!parsedColor || !context.allowColor)
5566 return nullptr; // This value is not a color or length and is invalid or
5567 // it is a color, but a color isn't allowed at this point.
5569 context.commitColor(parsedColor.release());
5575 if (context.allowBreak) {
5576 context.commitValue();
5577 if (context.values && context.values->length())
5578 return context.values.release();
5584 bool CSSPropertyParser::parseReflect(CSSPropertyID propId, bool important)
5586 // box-reflect: <direction> <offset> <mask>
5588 // Direction comes first.
5589 CSSParserValue* val = m_valueList->current();
5590 RefPtrWillBeRawPtr<CSSPrimitiveValue> direction = nullptr;
5596 direction = cssValuePool().createIdentifierValue(val->id);
5602 // The offset comes next.
5603 val = m_valueList->next();
5604 RefPtrWillBeRawPtr<CSSPrimitiveValue> offset = nullptr;
5606 offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
5608 if (!validUnit(val, FLength | FPercent))
5610 offset = createPrimitiveNumericValue(val);
5613 // Now for the mask.
5614 RefPtrWillBeRawPtr<CSSValue> mask = nullptr;
5615 val = m_valueList->next();
5617 mask = parseBorderImage(propId);
5622 RefPtrWillBeRawPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction.release(), offset.release(), mask.release());
5623 addProperty(propId, reflectValue.release(), important);
5624 m_valueList->next();
5628 bool CSSPropertyParser::parseFlex(CSSParserValueList* args, bool important)
5630 if (!args || !args->size() || args->size() > 3)
5632 static const double unsetValue = -1;
5633 double flexGrow = unsetValue;
5634 double flexShrink = unsetValue;
5635 RefPtrWillBeRawPtr<CSSPrimitiveValue> flexBasis = nullptr;
5637 while (CSSParserValue* arg = args->current()) {
5638 if (validUnit(arg, FNumber | FNonNeg)) {
5639 if (flexGrow == unsetValue)
5640 flexGrow = arg->fValue;
5641 else if (flexShrink == unsetValue)
5642 flexShrink = arg->fValue;
5643 else if (!arg->fValue) {
5644 // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
5645 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
5647 // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
5650 } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg)))
5651 flexBasis = parseValidPrimitive(arg->id, arg);
5653 // Not a valid arg for flex.
5659 if (flexGrow == unsetValue)
5661 if (flexShrink == unsetValue)
5664 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
5666 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
5667 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
5668 addProperty(CSSPropertyFlexBasis, flexBasis, important);
5672 bool CSSPropertyParser::parseObjectPosition(bool important)
5674 RefPtrWillBeRawPtr<CSSValue> xValue = nullptr;
5675 RefPtrWillBeRawPtr<CSSValue> yValue = nullptr;
5676 parseFillPosition(m_valueList.get(), xValue, yValue);
5677 if (!xValue || !yValue)
5680 CSSPropertyObjectPosition,
5681 createPrimitiveValuePair(toCSSPrimitiveValue(xValue.get()), toCSSPrimitiveValue(yValue.get()), Pair::KeepIdenticalValues),
5686 class BorderImageParseContext {
5689 BorderImageParseContext()
5690 : m_canAdvance(false)
5691 , m_allowCommit(true)
5692 , m_allowImage(true)
5693 , m_allowImageSlice(true)
5694 , m_allowRepeat(true)
5695 , m_allowForwardSlashOperator(false)
5696 , m_requireWidth(false)
5697 , m_requireOutset(false)
5700 bool canAdvance() const { return m_canAdvance; }
5701 void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
5703 bool allowCommit() const { return m_allowCommit; }
5704 bool allowImage() const { return m_allowImage; }
5705 bool allowImageSlice() const { return m_allowImageSlice; }
5706 bool allowRepeat() const { return m_allowRepeat; }
5707 bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; }
5709 bool requireWidth() const { return m_requireWidth; }
5710 bool requireOutset() const { return m_requireOutset; }
5712 void commitImage(PassRefPtrWillBeRawPtr<CSSValue> image)
5715 m_canAdvance = true;
5716 m_allowCommit = true;
5717 m_allowImage = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
5718 m_allowImageSlice = !m_imageSlice;
5719 m_allowRepeat = !m_repeat;
5721 void commitImageSlice(PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> slice)
5723 m_imageSlice = slice;
5724 m_canAdvance = true;
5725 m_allowCommit = m_allowForwardSlashOperator = true;
5726 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
5727 m_allowImage = !m_image;
5728 m_allowRepeat = !m_repeat;
5730 void commitForwardSlashOperator()
5732 m_canAdvance = true;
5733 m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowForwardSlashOperator = false;
5734 if (!m_borderSlice) {
5735 m_requireWidth = true;
5736 m_requireOutset = false;
5738 m_requireOutset = true;
5739 m_requireWidth = false;
5742 void commitBorderWidth(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> slice)
5744 m_borderSlice = slice;
5745 m_canAdvance = true;
5746 m_allowCommit = m_allowForwardSlashOperator = true;
5747 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
5748 m_allowImage = !m_image;
5749 m_allowRepeat = !m_repeat;
5751 void commitBorderOutset(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> outset)
5754 m_canAdvance = true;
5755 m_allowCommit = true;
5756 m_allowImageSlice = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
5757 m_allowImage = !m_image;
5758 m_allowRepeat = !m_repeat;
5760 void commitRepeat(PassRefPtrWillBeRawPtr<CSSValue> repeat)
5763 m_canAdvance = true;
5764 m_allowCommit = true;
5765 m_allowRepeat = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
5766 m_allowImageSlice = !m_imageSlice;
5767 m_allowImage = !m_image;
5770 PassRefPtrWillBeRawPtr<CSSValue> commitCSSValue()
5772 return createBorderImageValue(m_image, m_imageSlice.get(), m_borderSlice.get(), m_outset.get(), m_repeat.get());
5775 void commitMaskBoxImage(CSSPropertyParser* parser, bool important)
5777 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSource, parser, m_image, important);
5778 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSlice, parser, m_imageSlice.get(), important);
5779 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageWidth, parser, m_borderSlice.get(), important);
5780 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageOutset, parser, m_outset.get(), important);
5781 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageRepeat, parser, m_repeat.get(), important);
5784 void commitBorderImage(CSSPropertyParser* parser, bool important)
5786 commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
5787 commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice.get(), important);
5788 commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice.get(), important);
5789 commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset.get(), important);
5790 commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important);
5793 void commitBorderImageProperty(CSSPropertyID propId, CSSPropertyParser* parser, PassRefPtrWillBeRawPtr<CSSValue> value, bool important)
5796 parser->addProperty(propId, value, important);
5798 parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true);
5801 static bool buildFromParser(CSSPropertyParser&, CSSPropertyID, BorderImageParseContext&);
5807 bool m_allowImageSlice;
5809 bool m_allowForwardSlashOperator;
5811 bool m_requireWidth;
5812 bool m_requireOutset;
5814 RefPtrWillBeMember<CSSValue> m_image;
5815 RefPtrWillBeMember<CSSBorderImageSliceValue> m_imageSlice;
5816 RefPtrWillBeMember<CSSPrimitiveValue> m_borderSlice;
5817 RefPtrWillBeMember<CSSPrimitiveValue> m_outset;
5819 RefPtrWillBeMember<CSSValue> m_repeat;
5822 bool BorderImageParseContext::buildFromParser(CSSPropertyParser& parser, CSSPropertyID propId, BorderImageParseContext& context)
5824 CSSPropertyParser::ShorthandScope scope(&parser, propId);
5825 while (CSSParserValue* val = parser.m_valueList->current()) {
5826 context.setCanAdvance(false);
5828 if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(val))
5829 context.commitForwardSlashOperator();
5831 if (!context.canAdvance() && context.allowImage()) {
5832 if (val->unit == CSSPrimitiveValue::CSS_URI) {
5833 context.commitImage(parser.createCSSImageValueWithReferrer(val->string, parser.m_context.completeURL(val->string)));
5834 } else if (isGeneratedImageValue(val)) {
5835 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
5836 if (parser.parseGeneratedImage(parser.m_valueList.get(), value))
5837 context.commitImage(value.release());
5840 } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
5841 RefPtrWillBeRawPtr<CSSValue> value = parser.parseImageSet(parser.m_valueList.get());
5843 context.commitImage(value.release());
5846 } else if (val->id == CSSValueNone)
5847 context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone));
5850 if (!context.canAdvance() && context.allowImageSlice()) {
5851 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> imageSlice = nullptr;
5852 if (parser.parseBorderImageSlice(propId, imageSlice))
5853 context.commitImageSlice(imageSlice.release());
5856 if (!context.canAdvance() && context.allowRepeat()) {
5857 RefPtrWillBeRawPtr<CSSValue> repeat = nullptr;
5858 if (parser.parseBorderImageRepeat(repeat))
5859 context.commitRepeat(repeat.release());
5862 if (!context.canAdvance() && context.requireWidth()) {
5863 RefPtrWillBeRawPtr<CSSPrimitiveValue> borderSlice = nullptr;
5864 if (parser.parseBorderImageWidth(borderSlice))
5865 context.commitBorderWidth(borderSlice.release());
5868 if (!context.canAdvance() && context.requireOutset()) {
5869 RefPtrWillBeRawPtr<CSSPrimitiveValue> borderOutset = nullptr;
5870 if (parser.parseBorderImageOutset(borderOutset))
5871 context.commitBorderOutset(borderOutset.release());
5874 if (!context.canAdvance())
5877 parser.m_valueList->next();
5880 return context.allowCommit();
5883 bool CSSPropertyParser::parseBorderImageShorthand(CSSPropertyID propId, bool important)
5885 BorderImageParseContext context;
5886 if (BorderImageParseContext::buildFromParser(*this, propId, context)) {
5888 case CSSPropertyWebkitMaskBoxImage:
5889 context.commitMaskBoxImage(this, important);
5891 case CSSPropertyBorderImage:
5892 context.commitBorderImage(this, important);
5895 ASSERT_NOT_REACHED();
5902 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBorderImage(CSSPropertyID propId)
5904 BorderImageParseContext context;
5905 if (BorderImageParseContext::buildFromParser(*this, propId, context)) {
5906 return context.commitCSSValue();
5911 static bool isBorderImageRepeatKeyword(int id)
5913 return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
5916 bool CSSPropertyParser::parseBorderImageRepeat(RefPtrWillBeRawPtr<CSSValue>& result)
5918 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstValue = nullptr;
5919 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondValue = nullptr;
5920 CSSParserValue* val = m_valueList->current();
5923 if (isBorderImageRepeatKeyword(val->id))
5924 firstValue = cssValuePool().createIdentifierValue(val->id);
5928 val = m_valueList->next();
5930 if (isBorderImageRepeatKeyword(val->id))
5931 secondValue = cssValuePool().createIdentifierValue(val->id);
5932 else if (!inShorthand()) {
5933 // If we're not parsing a shorthand then we are invalid.
5936 // We need to rewind the value list, so that when its advanced we'll
5937 // end up back at this value.
5938 m_valueList->previous();
5939 secondValue = firstValue;
5942 secondValue = firstValue;
5944 result = createPrimitiveValuePair(firstValue, secondValue);
5948 class BorderImageSliceParseContext {
5951 BorderImageSliceParseContext(CSSPropertyParser* parser)
5953 , m_allowNumber(true)
5955 , m_allowFinalCommit(false)
5959 bool allowNumber() const { return m_allowNumber; }
5960 bool allowFill() const { return m_allowFill; }
5961 bool allowFinalCommit() const { return m_allowFinalCommit; }
5962 CSSPrimitiveValue* top() const { return m_top.get(); }
5964 void commitNumber(CSSParserValue* v)
5966 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
5978 m_allowNumber = !m_left;
5979 m_allowFinalCommit = true;
5982 void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; }
5984 PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
5986 // We need to clone and repeat values for any omissions.
6000 // Now build a rect value to hold all four of our primitive values.
6001 RefPtrWillBeRawPtr<Quad> quad = Quad::create();
6002 quad->setTop(m_top);
6003 quad->setRight(m_right);
6004 quad->setBottom(m_bottom);
6005 quad->setLeft(m_left);
6007 // Make our new border image value now.
6008 return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill);
6012 CSSPropertyParser* m_parser;
6016 bool m_allowFinalCommit;
6018 RefPtrWillBeMember<CSSPrimitiveValue> m_top;
6019 RefPtrWillBeMember<CSSPrimitiveValue> m_right;
6020 RefPtrWillBeMember<CSSPrimitiveValue> m_bottom;
6021 RefPtrWillBeMember<CSSPrimitiveValue> m_left;
6026 bool CSSPropertyParser::parseBorderImageSlice(CSSPropertyID propId, RefPtrWillBeRawPtr<CSSBorderImageSliceValue>& result)
6028 BorderImageSliceParseContext context(this);
6029 CSSParserValue* val;
6030 while ((val = m_valueList->current())) {
6031 // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
6032 if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, HTMLStandardMode)) {
6033 context.commitNumber(val);
6034 } else if (context.allowFill() && val->id == CSSValueFill)
6035 context.commitFill();
6036 else if (!inShorthand()) {
6037 // If we're not parsing a shorthand then we are invalid.
6040 if (context.allowFinalCommit()) {
6041 // We're going to successfully parse, but we don't want to consume this token.
6042 m_valueList->previous();
6046 m_valueList->next();
6049 if (context.allowFinalCommit()) {
6050 // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
6051 // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
6052 if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
6053 context.commitFill();
6055 // Need to fully commit as a single value.
6056 result = context.commitBorderImageSlice();
6063 class BorderImageQuadParseContext {
6066 BorderImageQuadParseContext(CSSPropertyParser* parser)
6068 , m_allowNumber(true)
6069 , m_allowFinalCommit(false)
6072 bool allowNumber() const { return m_allowNumber; }
6073 bool allowFinalCommit() const { return m_allowFinalCommit; }
6074 CSSPrimitiveValue* top() const { return m_top.get(); }
6076 void commitNumber(CSSParserValue* v)
6078 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = nullptr;
6079 if (v->id == CSSValueAuto)
6080 val = cssValuePool().createIdentifierValue(v->id);
6082 val = m_parser->createPrimitiveNumericValue(v);
6095 m_allowNumber = !m_left;
6096 m_allowFinalCommit = true;
6099 void setTop(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val) { m_top = val; }
6101 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> commitBorderImageQuad()
6103 // We need to clone and repeat values for any omissions.
6117 // Now build a quad value to hold all four of our primitive values.
6118 RefPtrWillBeRawPtr<Quad> quad = Quad::create();
6119 quad->setTop(m_top);
6120 quad->setRight(m_right);
6121 quad->setBottom(m_bottom);
6122 quad->setLeft(m_left);
6124 // Make our new value now.
6125 return cssValuePool().createValue(quad.release());
6129 CSSPropertyParser* m_parser;
6132 bool m_allowFinalCommit;
6134 RefPtrWillBeMember<CSSPrimitiveValue> m_top;
6135 RefPtrWillBeMember<CSSPrimitiveValue> m_right;
6136 RefPtrWillBeMember<CSSPrimitiveValue> m_bottom;
6137 RefPtrWillBeMember<CSSPrimitiveValue> m_left;
6140 bool CSSPropertyParser::parseBorderImageQuad(Units validUnits, RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
6142 BorderImageQuadParseContext context(this);
6143 CSSParserValue* val;
6144 while ((val = m_valueList->current())) {
6145 if (context.allowNumber() && (validUnit(val, validUnits, HTMLStandardMode) || val->id == CSSValueAuto)) {
6146 context.commitNumber(val);
6147 } else if (!inShorthand()) {
6148 // If we're not parsing a shorthand then we are invalid.
6151 if (context.allowFinalCommit())
6152 m_valueList->previous(); // The shorthand loop will advance back to this point.
6155 m_valueList->next();
6158 if (context.allowFinalCommit()) {
6159 // Need to fully commit as a single value.
6160 result = context.commitBorderImageQuad();
6166 bool CSSPropertyParser::parseBorderImageWidth(RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
6168 return parseBorderImageQuad(FLength | FNumber | FNonNeg | FPercent, result);
6171 bool CSSPropertyParser::parseBorderImageOutset(RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
6173 return parseBorderImageQuad(FLength | FNumber | FNonNeg, result);
6176 bool CSSPropertyParser::parseBorderRadius(CSSPropertyID propId, bool important)
6178 unsigned num = m_valueList->size();
6182 ShorthandScope scope(this, propId);
6183 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
6185 // Zero initialize the array of raw pointers.
6186 memset(&radii, 0, sizeof(radii));
6189 unsigned indexAfterSlash = 0;
6190 for (unsigned i = 0; i < num; ++i) {
6191 CSSParserValue* value = m_valueList->valueAt(i);
6192 if (value->unit == CSSParserValue::Operator) {
6193 if (value->iValue != '/')
6196 if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
6199 indexAfterSlash = i + 1;
6200 completeBorderRadii(radii[0]);
6204 if (i - indexAfterSlash >= 4)
6207 if (!validUnit(value, FLength | FPercent | FNonNeg))
6210 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
6212 if (!indexAfterSlash) {
6213 radii[0][i] = radius;
6215 // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
6216 if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
6217 indexAfterSlash = 1;
6218 completeBorderRadii(radii[0]);
6221 radii[1][i - indexAfterSlash] = radius.release();
6224 if (!indexAfterSlash) {
6225 completeBorderRadii(radii[0]);
6226 for (unsigned i = 0; i < 4; ++i)
6227 radii[1][i] = radii[0][i];
6229 completeBorderRadii(radii[1]);
6231 ImplicitScope implicitScope(this, PropertyImplicit);
6232 addProperty(CSSPropertyBorderTopLeftRadius, createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()), important);
6233 addProperty(CSSPropertyBorderTopRightRadius, createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()), important);
6234 addProperty(CSSPropertyBorderBottomRightRadius, createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()), important);
6235 addProperty(CSSPropertyBorderBottomLeftRadius, createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()), important);
6239 bool CSSPropertyParser::parseAspectRatio(bool important)
6241 unsigned num = m_valueList->size();
6242 if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
6243 addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(CSSValueNone), important);
6250 CSSParserValue* lvalue = m_valueList->valueAt(0);
6251 CSSParserValue* op = m_valueList->valueAt(1);
6252 CSSParserValue* rvalue = m_valueList->valueAt(2);
6254 if (!isForwardSlashOperator(op))
6257 if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
6260 if (!lvalue->fValue || !rvalue->fValue)
6263 addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important);
6268 bool CSSPropertyParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important)
6270 enum { ID, VAL } state = ID;
6272 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
6273 RefPtrWillBeRawPtr<CSSPrimitiveValue> counterName = nullptr;
6276 CSSParserValue* val = m_valueList->current();
6279 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
6280 counterName = createPrimitiveStringValue(val);
6282 m_valueList->next();
6287 int i = defaultValue;
6288 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
6289 i = clampToInteger(val->fValue);
6290 m_valueList->next();
6293 list->append(createPrimitiveValuePair(counterName.release(),
6294 cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER)));
6302 if (list->length() > 0) {
6303 addProperty(propId, list.release(), important);
6310 // This should go away once we drop support for -webkit-gradient
6311 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
6313 RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
6314 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
6315 if ((equalIgnoringCase(a, "left") && horizontal)
6316 || (equalIgnoringCase(a, "top") && !horizontal))
6317 result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
6318 else if ((equalIgnoringCase(a, "right") && horizontal)
6319 || (equalIgnoringCase(a, "bottom") && !horizontal))
6320 result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
6321 else if (equalIgnoringCase(a, "center"))
6322 result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
6323 } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE) {
6324 result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitType>(a->unit));
6329 bool parseDeprecatedGradientColorStop(CSSPropertyParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
6331 if (a->unit != CSSParserValue::Function)
6334 if (!equalIgnoringCase(a->function->name, "from(") &&
6335 !equalIgnoringCase(a->function->name, "to(") &&
6336 !equalIgnoringCase(a->function->name, "color-stop("))
6339 CSSParserValueList* args = a->function->args.get();
6343 if (equalIgnoringCase(a->function->name, "from(")
6344 || equalIgnoringCase(a->function->name, "to(")) {
6345 // The "from" and "to" stops expect 1 argument.
6346 if (args->size() != 1)
6349 if (equalIgnoringCase(a->function->name, "from("))
6350 stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
6352 stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
6354 CSSValueID id = args->current()->id;
6355 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
6356 stop.m_color = cssValuePool().createIdentifierValue(id);
6358 stop.m_color = p->parseColor(args->current());
6363 // The "color-stop" function expects 3 arguments.
6364 if (equalIgnoringCase(a->function->name, "color-stop(")) {
6365 if (args->size() != 3)
6368 CSSParserValue* stopArg = args->current();
6369 if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
6370 stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
6371 else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
6372 stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
6376 stopArg = args->next();
6377 if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
6380 stopArg = args->next();
6381 CSSValueID id = stopArg->id;
6382 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
6383 stop.m_color = cssValuePool().createIdentifierValue(id);
6385 stop.m_color = p->parseColor(stopArg);
6393 bool CSSPropertyParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient)
6395 // Walk the arguments.
6396 CSSParserValueList* args = valueList->current()->function->args.get();
6397 if (!args || args->size() == 0)
6400 // The first argument is the gradient type. It is an identifier.
6401 CSSGradientType gradientType;
6402 CSSParserValue* a = args->current();
6403 if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
6405 if (equalIgnoringCase(a, "linear"))
6406 gradientType = CSSDeprecatedLinearGradient;
6407 else if (equalIgnoringCase(a, "radial"))
6408 gradientType = CSSDeprecatedRadialGradient;
6412 RefPtrWillBeRawPtr<CSSGradientValue> result = nullptr;
6413 switch (gradientType) {
6414 case CSSDeprecatedLinearGradient:
6415 result = CSSLinearGradientValue::create(NonRepeating, gradientType);
6417 case CSSDeprecatedRadialGradient:
6418 result = CSSRadialGradientValue::create(NonRepeating, gradientType);
6421 // The rest of the gradient types shouldn't appear here.
6422 ASSERT_NOT_REACHED();
6430 // Next comes the starting point for the gradient as an x y pair. There is no
6431 // comma between the x and the y values.
6432 // First X. It can be left, right, number or percent.
6436 RefPtrWillBeRawPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
6439 result->setFirstX(point.release());
6441 // First Y. It can be top, bottom, number or percent.
6445 point = parseDeprecatedGradientPoint(a, false);
6448 result->setFirstY(point.release());
6450 // Comma after the first point.
6455 // For radial gradients only, we now expect a numeric radius.
6456 if (gradientType == CSSDeprecatedRadialGradient) {
6458 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
6460 toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
6462 // Comma after the first radius.
6468 // Next is the ending point for the gradient as an x, y pair.
6469 // Second X. It can be left, right, number or percent.
6473 point = parseDeprecatedGradientPoint(a, true);
6476 result->setSecondX(point.release());
6478 // Second Y. It can be top, bottom, number or percent.
6482 point = parseDeprecatedGradientPoint(a, false);
6485 result->setSecondY(point.release());
6487 // For radial gradients only, we now expect the second radius.
6488 if (gradientType == CSSDeprecatedRadialGradient) {
6489 // Comma after the second point.
6495 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
6497 toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
6500 // We now will accept any number of stops (0 or more).
6503 // Look for the comma before the next stop.
6507 // Now examine the stop itself.
6512 // The function name needs to be one of "from", "to", or "color-stop."
6513 CSSGradientColorStop stop;
6514 if (!parseDeprecatedGradientColorStop(this, a, stop))
6516 result->addStop(stop);
6522 gradient = result.release();
6526 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
6528 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
6534 isHorizontal = true;
6537 case CSSValueBottom:
6538 isHorizontal = false;
6543 return cssValuePool().createIdentifierValue(a->id);
6546 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSPropertyParser* p, CSSParserValue* value)
6548 CSSValueID id = value->id;
6549 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
6550 return cssValuePool().createIdentifierValue(id);
6552 return p->parseColor(value);
6555 bool CSSPropertyParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6557 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient);
6559 // Walk the arguments.
6560 CSSParserValueList* args = valueList->current()->function->args.get();
6561 if (!args || !args->size())
6564 CSSParserValue* a = args->current();
6568 bool expectComma = false;
6570 if (validUnit(a, FAngle, HTMLStandardMode)) {
6571 result->setAngle(createPrimitiveNumericValue(a));
6576 // Look one or two optional keywords that indicate a side or corner.
6577 RefPtrWillBeRawPtr<CSSPrimitiveValue> startX = nullptr;
6578 RefPtrWillBeRawPtr<CSSPrimitiveValue> startY = nullptr;
6580 RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr;
6581 bool isHorizontal = false;
6582 if ((location = valueFromSideKeyword(a, isHorizontal))) {
6588 if ((a = args->next())) {
6589 if ((location = valueFromSideKeyword(a, isHorizontal))) {
6607 if (!startX && !startY)
6608 startY = cssValuePool().createIdentifierValue(CSSValueTop);
6610 result->setFirstX(startX.release());
6611 result->setFirstY(startY.release());
6614 if (!parseGradientColorStops(args, result.get(), expectComma))
6617 if (!result->stopCount())
6620 gradient = result.release();
6624 bool CSSPropertyParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6626 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
6628 // Walk the arguments.
6629 CSSParserValueList* args = valueList->current()->function->args.get();
6630 if (!args || !args->size())
6633 CSSParserValue* a = args->current();
6637 bool expectComma = false;
6639 // Optional background-position
6640 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
6641 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
6642 // parse2ValuesFillPosition advances the args next pointer.
6643 parse2ValuesFillPosition(args, centerX, centerY);
6644 a = args->current();
6648 if (centerX || centerY) {
6658 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
6659 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
6660 // CSS3 radial gradients always share the same start and end point.
6661 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
6662 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
6664 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
6665 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr;
6667 // Optional shape and/or size in any order.
6668 for (int i = 0; i < 2; ++i) {
6669 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
6672 bool foundValue = false;
6674 case CSSValueCircle:
6675 case CSSValueEllipse:
6676 shapeValue = cssValuePool().createIdentifierValue(a->id);
6679 case CSSValueClosestSide:
6680 case CSSValueClosestCorner:
6681 case CSSValueFarthestSide:
6682 case CSSValueFarthestCorner:
6683 case CSSValueContain:
6685 sizeValue = cssValuePool().createIdentifierValue(a->id);
6701 result->setShape(shapeValue);
6702 result->setSizingBehavior(sizeValue);
6704 // Or, two lengths or percentages
6705 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr;
6706 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr;
6708 if (!shapeValue && !sizeValue) {
6709 if (validUnit(a, FLength | FPercent)) {
6710 horizontalSize = createPrimitiveNumericValue(a);
6718 if (validUnit(a, FLength | FPercent)) {
6719 verticalSize = createPrimitiveNumericValue(a);
6728 // Must have neither or both.
6729 if (!horizontalSize != !verticalSize)
6732 result->setEndHorizontalSize(horizontalSize);
6733 result->setEndVerticalSize(verticalSize);
6735 if (!parseGradientColorStops(args, result.get(), expectComma))
6738 gradient = result.release();
6742 bool CSSPropertyParser::parseLinearGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6744 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient);
6746 CSSParserValueList* args = valueList->current()->function->args.get();
6747 if (!args || !args->size())
6750 CSSParserValue* a = args->current();
6754 bool expectComma = false;
6756 if (validUnit(a, FAngle, HTMLStandardMode)) {
6757 result->setAngle(createPrimitiveNumericValue(a));
6761 } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) {
6762 // to [ [left | right] || [top | bottom] ]
6767 RefPtrWillBeRawPtr<CSSPrimitiveValue> endX = nullptr;
6768 RefPtrWillBeRawPtr<CSSPrimitiveValue> endY = nullptr;
6769 RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr;
6770 bool isHorizontal = false;
6772 location = valueFromSideKeyword(a, isHorizontal);
6785 location = valueFromSideKeyword(a, isHorizontal);
6801 result->setFirstX(endX.release());
6802 result->setFirstY(endY.release());
6805 if (!parseGradientColorStops(args, result.get(), expectComma))
6808 if (!result->stopCount())
6811 gradient = result.release();
6815 bool CSSPropertyParser::parseRadialGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6817 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
6819 CSSParserValueList* args = valueList->current()->function->args.get();
6820 if (!args || !args->size())
6823 CSSParserValue* a = args->current();
6827 bool expectComma = false;
6829 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
6830 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr;
6831 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr;
6832 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr;
6834 // First part of grammar, the size/shape clause:
6835 // [ circle || <length> ] |
6836 // [ ellipse || [ <length> | <percentage> ]{2} ] |
6837 // [ [ circle | ellipse] || <size-keyword> ]
6838 for (int i = 0; i < 3; ++i) {
6839 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
6840 bool badIdent = false;
6842 case CSSValueCircle:
6843 case CSSValueEllipse:
6846 shapeValue = cssValuePool().createIdentifierValue(a->id);
6848 case CSSValueClosestSide:
6849 case CSSValueClosestCorner:
6850 case CSSValueFarthestSide:
6851 case CSSValueFarthestCorner:
6852 if (sizeValue || horizontalSize)
6854 sizeValue = cssValuePool().createIdentifierValue(a->id);
6866 } else if (validUnit(a, FLength | FPercent)) {
6868 if (sizeValue || horizontalSize)
6870 horizontalSize = createPrimitiveNumericValue(a);
6876 if (validUnit(a, FLength | FPercent)) {
6877 verticalSize = createPrimitiveNumericValue(a);
6887 // You can specify size as a keyword or a length/percentage, not both.
6888 if (sizeValue && horizontalSize)
6890 // Circles must have 0 or 1 lengths.
6891 if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize)
6893 // Ellipses must have 0 or 2 length/percentages.
6894 if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
6896 // If there's only one size, it must be a length.
6897 if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
6900 result->setShape(shapeValue);
6901 result->setSizingBehavior(sizeValue);
6902 result->setEndHorizontalSize(horizontalSize);
6903 result->setEndVerticalSize(verticalSize);
6905 // Second part of grammar, the center-position clause:
6907 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
6908 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
6909 if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) {
6914 parseFillPosition(args, centerX, centerY);
6915 if (!(centerX && centerY))
6918 a = args->current();
6921 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
6922 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
6923 // Right now, CSS radial gradients have the same start and end centers.
6924 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
6925 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
6928 if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
6931 if (!parseGradientColorStops(args, result.get(), expectComma))
6934 gradient = result.release();
6938 bool CSSPropertyParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
6940 CSSParserValue* a = valueList->current();
6942 // Now look for color stops.
6944 // Look for the comma before the next stop.
6949 a = valueList->next();
6954 // <color-stop> = <color> [ <percentage> | <length> ]?
6955 CSSGradientColorStop stop;
6956 stop.m_color = parseGradientColorOrKeyword(this, a);
6960 a = valueList->next();
6962 if (validUnit(a, FLength | FPercent)) {
6963 stop.m_position = createPrimitiveNumericValue(a);
6964 a = valueList->next();
6968 gradient->addStop(stop);
6972 // Must have 2 or more stops to be valid.
6973 return gradient->stopCount() >= 2;
6976 bool CSSPropertyParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value)
6978 CSSParserValue* val = valueList->current();
6980 if (val->unit != CSSParserValue::Function)
6983 if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) {
6984 // FIXME: This should send a deprecation message.
6985 if (m_context.useCounter())
6986 m_context.useCounter()->count(UseCounter::DeprecatedWebKitGradient);
6987 return parseDeprecatedGradient(valueList, value);
6990 if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")) {
6991 // FIXME: This should send a deprecation message.
6992 if (m_context.useCounter())
6993 m_context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGradient);
6994 return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
6997 if (equalIgnoringCase(val->function->name, "linear-gradient("))
6998 return parseLinearGradient(valueList, value, NonRepeating);
7000 if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")) {
7001 // FIXME: This should send a deprecation message.
7002 if (m_context.useCounter())
7003 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLinearGradient);
7004 return parseDeprecatedLinearGradient(valueList, value, Repeating);
7007 if (equalIgnoringCase(val->function->name, "repeating-linear-gradient("))
7008 return parseLinearGradient(valueList, value, Repeating);
7010 if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")) {
7011 // FIXME: This should send a deprecation message.
7012 if (m_context.useCounter())
7013 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGradient);
7014 return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
7017 if (equalIgnoringCase(val->function->name, "radial-gradient("))
7018 return parseRadialGradient(valueList, value, NonRepeating);
7020 if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")) {
7021 if (m_context.useCounter())
7022 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingRadialGradient);
7023 return parseDeprecatedRadialGradient(valueList, value, Repeating);
7026 if (equalIgnoringCase(val->function->name, "repeating-radial-gradient("))
7027 return parseRadialGradient(valueList, value, Repeating);
7029 if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
7030 return parseCanvas(valueList, value);
7032 if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
7033 return parseCrossfade(valueList, value);
7038 bool CSSPropertyParser::parseCrossfade(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& crossfade)
7040 // Walk the arguments.
7041 CSSParserValueList* args = valueList->current()->function->args.get();
7042 if (!args || args->size() != 5)
7044 CSSParserValue* a = args->current();
7045 RefPtrWillBeRawPtr<CSSValue> fromImageValue = nullptr;
7046 RefPtrWillBeRawPtr<CSSValue> toImageValue = nullptr;
7048 // The first argument is the "from" image. It is a fill image.
7049 if (!a || !parseFillImage(args, fromImageValue))
7058 // The second argument is the "to" image. It is a fill image.
7059 if (!a || !parseFillImage(args, toImageValue))
7068 // The third argument is the crossfade value. It is a percentage or a fractional number.
7069 RefPtrWillBeRawPtr<CSSPrimitiveValue> percentage = nullptr;
7073 if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7074 percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
7075 else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
7076 percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
7080 RefPtrWillBeRawPtr<CSSCrossfadeValue> result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
7081 result->setPercentage(percentage);
7088 bool CSSPropertyParser::parseCanvas(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& canvas)
7090 // Walk the arguments.
7091 CSSParserValueList* args = valueList->current()->function->args.get();
7092 if (!args || args->size() != 1)
7095 // The first argument is the canvas name. It is an identifier.
7096 CSSParserValue* value = args->current();
7097 if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
7100 canvas = CSSCanvasValue::create(value->string);
7104 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseImageSet(CSSParserValueList* valueList)
7106 CSSParserValue* function = valueList->current();
7108 if (function->unit != CSSParserValue::Function)
7111 CSSParserValueList* functionArgs = valueList->current()->function->args.get();
7112 if (!functionArgs || !functionArgs->size() || !functionArgs->current())
7115 RefPtrWillBeRawPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
7117 CSSParserValue* arg = functionArgs->current();
7119 if (arg->unit != CSSPrimitiveValue::CSS_URI)
7122 RefPtrWillBeRawPtr<CSSValue> image = createCSSImageValueWithReferrer(arg->string, completeURL(arg->string));
7123 imageSet->append(image);
7125 arg = functionArgs->next();
7126 if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
7129 double imageScaleFactor = 0;
7130 const String& string = arg->string;
7131 unsigned length = string.length();
7134 if (string.is8Bit()) {
7135 const LChar* start = string.characters8();
7136 parseDouble(start, start + length, 'x', imageScaleFactor);
7138 const UChar* start = string.characters16();
7139 parseDouble(start, start + length, 'x', imageScaleFactor);
7141 if (imageScaleFactor <= 0)
7143 imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER));
7145 // If there are no more arguments, we're done.
7146 arg = functionArgs->next();
7150 // If there are more arguments, they should be after a comma.
7154 // Skip the comma and move on to the next argument.
7155 arg = functionArgs->next();
7158 return imageSet.release();
7161 bool CSSPropertyParser::parseWillChange(bool important)
7163 ASSERT(RuntimeEnabledFeatures::cssWillChangeEnabled());
7165 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
7166 if (m_valueList->current()->id == CSSValueAuto) {
7167 if (m_valueList->next())
7171 CSSParserValue* currentValue;
7172 bool expectComma = false;
7174 // Every comma-separated list of CSS_IDENTs is a valid will-change value,
7175 // unless the list includes an explicitly disallowed CSS_IDENT.
7176 while ((currentValue = m_valueList->current())) {
7178 if (!isComma(currentValue))
7180 expectComma = false;
7181 m_valueList->next();
7185 if (currentValue->unit != CSSPrimitiveValue::CSS_IDENT)
7188 CSSPropertyID property = cssPropertyID(currentValue->string);
7189 if (property && RuntimeCSSEnabled::isCSSPropertyEnabled(property)) {
7190 // Now "all" is used by both CSSValue and CSSPropertyValue.
7191 // Need to return false when currentValue is CSSPropertyAll.
7192 if (property == CSSPropertyWillChange || property == CSSPropertyAll)
7194 values->append(cssValuePool().createIdentifierValue(property));
7196 switch (currentValue->id) {
7200 case CSSValueDefault:
7201 case CSSValueInitial:
7202 case CSSValueInherit:
7204 case CSSValueContents:
7205 case CSSValueScrollPosition:
7206 values->append(cssValuePool().createIdentifierValue(currentValue->id));
7213 m_valueList->next();
7216 addProperty(CSSPropertyWillChange, values.release(), important);
7220 static void filterInfoForName(const CSSParserString& name, CSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
7222 if (equalIgnoringCase(name, "grayscale("))
7223 filterType = CSSFilterValue::GrayscaleFilterOperation;
7224 else if (equalIgnoringCase(name, "sepia("))
7225 filterType = CSSFilterValue::SepiaFilterOperation;
7226 else if (equalIgnoringCase(name, "saturate("))
7227 filterType = CSSFilterValue::SaturateFilterOperation;
7228 else if (equalIgnoringCase(name, "hue-rotate("))
7229 filterType = CSSFilterValue::HueRotateFilterOperation;
7230 else if (equalIgnoringCase(name, "invert("))
7231 filterType = CSSFilterValue::InvertFilterOperation;
7232 else if (equalIgnoringCase(name, "opacity("))
7233 filterType = CSSFilterValue::OpacityFilterOperation;
7234 else if (equalIgnoringCase(name, "brightness("))
7235 filterType = CSSFilterValue::BrightnessFilterOperation;
7236 else if (equalIgnoringCase(name, "contrast("))
7237 filterType = CSSFilterValue::ContrastFilterOperation;
7238 else if (equalIgnoringCase(name, "blur("))
7239 filterType = CSSFilterValue::BlurFilterOperation;
7240 else if (equalIgnoringCase(name, "drop-shadow(")) {
7241 filterType = CSSFilterValue::DropShadowFilterOperation;
7242 maximumArgumentCount = 4; // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
7246 PassRefPtrWillBeRawPtr<CSSFilterValue> CSSPropertyParser::parseBuiltinFilterArguments(CSSParserValueList* args, CSSFilterValue::FilterOperationType filterType)
7248 RefPtrWillBeRawPtr<CSSFilterValue> filterValue = CSSFilterValue::create(filterType);
7251 switch (filterType) {
7252 case CSSFilterValue::GrayscaleFilterOperation:
7253 case CSSFilterValue::SepiaFilterOperation:
7254 case CSSFilterValue::SaturateFilterOperation:
7255 case CSSFilterValue::InvertFilterOperation:
7256 case CSSFilterValue::OpacityFilterOperation:
7257 case CSSFilterValue::ContrastFilterOperation: {
7258 // One optional argument, 0-1 or 0%-100%, if missing use 100%.
7259 if (args->size() > 1)
7263 CSSParserValue* value = args->current();
7264 if (!validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode))
7267 double amount = value->fValue;
7269 // Saturate and Contrast allow values over 100%.
7270 if (filterType != CSSFilterValue::SaturateFilterOperation
7271 && filterType != CSSFilterValue::ContrastFilterOperation) {
7272 double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
7273 if (amount > maxAllowed)
7277 filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitType>(value->unit)));
7281 case CSSFilterValue::BrightnessFilterOperation: {
7282 // One optional argument, if missing use 100%.
7283 if (args->size() > 1)
7287 CSSParserValue* value = args->current();
7288 if (!validUnit(value, FNumber | FPercent, HTMLStandardMode))
7291 filterValue->append(cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitType>(value->unit)));
7295 case CSSFilterValue::HueRotateFilterOperation: {
7296 // hue-rotate() takes one optional angle.
7297 if (args->size() > 1)
7301 CSSParserValue* argument = args->current();
7302 if (!validUnit(argument, FAngle, HTMLStandardMode))
7305 filterValue->append(createPrimitiveNumericValue(argument));
7309 case CSSFilterValue::BlurFilterOperation: {
7310 // Blur takes a single length. Zero parameters are allowed.
7311 if (args->size() > 1)
7315 CSSParserValue* argument = args->current();
7316 if (!validUnit(argument, FLength | FNonNeg, HTMLStandardMode))
7319 filterValue->append(createPrimitiveNumericValue(argument));
7323 case CSSFilterValue::DropShadowFilterOperation: {
7324 // drop-shadow() takes a single shadow.
7325 RefPtrWillBeRawPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter);
7326 if (!shadowValueList || shadowValueList->length() != 1)
7329 filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0));
7333 ASSERT_NOT_REACHED();
7335 return filterValue.release();
7338 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFilter()
7343 // The filter is a list of functional primitives that specify individual operations.
7344 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7345 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7346 if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function))
7349 CSSFilterValue::FilterOperationType filterType = CSSFilterValue::UnknownFilterOperation;
7351 // See if the specified primitive is one we understand.
7352 if (value->unit == CSSPrimitiveValue::CSS_URI) {
7353 RefPtrWillBeRawPtr<CSSFilterValue> referenceFilterValue = CSSFilterValue::create(CSSFilterValue::ReferenceFilterOperation);
7354 list->append(referenceFilterValue);
7355 referenceFilterValue->append(CSSSVGDocumentValue::create(value->string));
7357 const CSSParserString name = value->function->name;
7358 unsigned maximumArgumentCount = 1;
7360 filterInfoForName(name, filterType, maximumArgumentCount);
7362 if (filterType == CSSFilterValue::UnknownFilterOperation)
7365 CSSParserValueList* args = value->function->args.get();
7369 RefPtrWillBeRawPtr<CSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType);
7373 list->append(filterValue);
7377 return list.release();
7379 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseTransformOrigin()
7381 CSSParserValue* value = m_valueList->current();
7382 CSSValueID id = value->id;
7383 RefPtrWillBeRawPtr<CSSValue> xValue = nullptr;
7384 RefPtrWillBeRawPtr<CSSValue> yValue = nullptr;
7385 RefPtrWillBeRawPtr<CSSValue> zValue = nullptr;
7386 if (id == CSSValueLeft || id == CSSValueRight) {
7387 xValue = cssValuePool().createIdentifierValue(id);
7388 } else if (id == CSSValueTop || id == CSSValueBottom) {
7389 yValue = cssValuePool().createIdentifierValue(id);
7390 } else if (id == CSSValueCenter) {
7391 // Unresolved as to whether this is X or Y.
7392 } else if (validUnit(value, FPercent | FLength)) {
7393 xValue = createPrimitiveNumericValue(value);
7398 if ((value = m_valueList->next())) {
7400 if (!xValue && (id == CSSValueLeft || id == CSSValueRight)) {
7401 xValue = cssValuePool().createIdentifierValue(id);
7402 } else if (!yValue && (id == CSSValueTop || id == CSSValueBottom)) {
7403 yValue = cssValuePool().createIdentifierValue(id);
7404 } else if (id == CSSValueCenter) {
7406 } else if (!yValue && validUnit(value, FPercent | FLength)) {
7407 yValue = createPrimitiveNumericValue(value);
7412 // If X or Y have not been resolved, they must be center.
7414 xValue = cssValuePool().createIdentifierValue(CSSValueCenter);
7416 yValue = cssValuePool().createIdentifierValue(CSSValueCenter);
7418 if ((value = m_valueList->next())) {
7419 if (!validUnit(value, FLength))
7421 zValue = createPrimitiveNumericValue(value);
7423 if ((value = m_valueList->next()))
7426 } else if (!xValue) {
7428 xValue = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
7430 xValue = cssValuePool().createIdentifierValue(CSSValueCenter);
7434 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7435 list->append(xValue.release());
7437 list->append(yValue.release());
7439 list->append(zValue.release());
7440 return list.release();
7443 bool CSSPropertyParser::parseWebkitTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtrWillBeRawPtr<CSSValue>& value, RefPtrWillBeRawPtr<CSSValue>& value2, RefPtrWillBeRawPtr<CSSValue>& value3)
7448 if (propId == CSSPropertyWebkitTransformOrigin) {
7449 propId1 = CSSPropertyWebkitTransformOriginX;
7450 propId2 = CSSPropertyWebkitTransformOriginY;
7451 propId3 = CSSPropertyWebkitTransformOriginZ;
7455 case CSSPropertyWebkitTransformOrigin:
7456 if (!parseWebkitTransformOriginShorthand(value, value2, value3))
7458 // parseWebkitTransformOriginShorthand advances the m_valueList pointer
7460 case CSSPropertyWebkitTransformOriginX: {
7461 value = parseFillPositionX(m_valueList.get());
7463 m_valueList->next();
7466 case CSSPropertyWebkitTransformOriginY: {
7467 value = parseFillPositionY(m_valueList.get());
7469 m_valueList->next();
7472 case CSSPropertyWebkitTransformOriginZ: {
7473 if (validUnit(m_valueList->current(), FLength))
7474 value = createPrimitiveNumericValue(m_valueList->current());
7476 m_valueList->next();
7480 ASSERT_NOT_REACHED();
7487 bool CSSPropertyParser::parseWebkitPerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtrWillBeRawPtr<CSSValue>& value, RefPtrWillBeRawPtr<CSSValue>& value2)
7491 if (propId == CSSPropertyWebkitPerspectiveOrigin) {
7492 propId1 = CSSPropertyWebkitPerspectiveOriginX;
7493 propId2 = CSSPropertyWebkitPerspectiveOriginY;
7497 case CSSPropertyWebkitPerspectiveOrigin:
7498 if (m_valueList->size() > 2)
7500 parse2ValuesFillPosition(m_valueList.get(), value, value2);
7502 case CSSPropertyWebkitPerspectiveOriginX: {
7503 value = parseFillPositionX(m_valueList.get());
7505 m_valueList->next();
7508 case CSSPropertyWebkitPerspectiveOriginY: {
7509 value = parseFillPositionY(m_valueList.get());
7511 m_valueList->next();
7515 ASSERT_NOT_REACHED();
7522 bool CSSPropertyParser::parseTouchAction(bool important)
7524 if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
7527 CSSParserValue* value = m_valueList->current();
7528 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7529 if (m_valueList->size() == 1 && value && (value->id == CSSValueAuto || value->id == CSSValueNone || value->id == CSSValueManipulation)) {
7530 list->append(cssValuePool().createIdentifierValue(value->id));
7531 addProperty(CSSPropertyTouchAction, list.release(), important);
7532 m_valueList->next();
7536 bool isValid = true;
7537 while (isValid && value) {
7538 switch (value->id) {
7540 case CSSValuePanY: {
7541 RefPtrWillBeRawPtr<CSSValue> panValue = cssValuePool().createIdentifierValue(value->id);
7542 if (list->hasValue(panValue.get())) {
7546 list->append(panValue.release());
7554 value = m_valueList->next();
7557 if (list->length() && isValid) {
7558 addProperty(CSSPropertyTouchAction, list.release(), important);
7565 void CSSPropertyParser::addTextDecorationProperty(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important)
7567 // The text-decoration-line property takes priority over text-decoration, unless the latter has important priority set.
7568 if (propId == CSSPropertyTextDecoration && !important && !inShorthand()) {
7569 for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
7570 if (m_parsedProperties[i].id() == CSSPropertyTextDecorationLine)
7574 addProperty(propId, value, important);
7577 bool CSSPropertyParser::parseTextDecoration(CSSPropertyID propId, bool important)
7579 if (propId == CSSPropertyTextDecorationLine
7580 && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
7583 CSSParserValue* value = m_valueList->current();
7584 if (value && value->id == CSSValueNone) {
7585 addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
7586 m_valueList->next();
7590 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7591 bool isValid = true;
7592 while (isValid && value) {
7593 switch (value->id) {
7594 case CSSValueUnderline:
7595 case CSSValueOverline:
7596 case CSSValueLineThrough:
7598 list->append(cssValuePool().createIdentifierValue(value->id));
7605 value = m_valueList->next();
7608 // Values are either valid or in shorthand scope.
7609 if (list->length() && (isValid || inShorthand())) {
7610 addTextDecorationProperty(propId, list.release(), important);
7617 bool CSSPropertyParser::parseTextUnderlinePosition(bool important)
7619 // The text-underline-position property has syntax "auto | [ under || [ left | right ] ]".
7620 // However, values 'left' and 'right' are not implemented yet, so we will parse syntax
7621 // "auto | under" for now.
7622 CSSParserValue* value = m_valueList->current();
7623 switch (value->id) {
7626 if (m_valueList->next())
7628 addProperty(CSSPropertyTextUnderlinePosition, cssValuePool().createIdentifierValue(value->id), important);
7635 bool CSSPropertyParser::parseTextEmphasisStyle(bool important)
7637 unsigned valueListSize = m_valueList->size();
7639 RefPtrWillBeRawPtr<CSSPrimitiveValue> fill = nullptr;
7640 RefPtrWillBeRawPtr<CSSPrimitiveValue> shape = nullptr;
7642 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7643 if (value->unit == CSSPrimitiveValue::CSS_STRING) {
7644 if (fill || shape || (valueListSize != 1 && !inShorthand()))
7646 addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important);
7647 m_valueList->next();
7651 if (value->id == CSSValueNone) {
7652 if (fill || shape || (valueListSize != 1 && !inShorthand()))
7654 addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important);
7655 m_valueList->next();
7659 if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
7662 fill = cssValuePool().createIdentifierValue(value->id);
7663 } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
7666 shape = cssValuePool().createIdentifierValue(value->id);
7667 } else if (!inShorthand())
7673 if (fill && shape) {
7674 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
7675 parsedValues->append(fill.release());
7676 parsedValues->append(shape.release());
7677 addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
7681 addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
7685 addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
7692 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTextIndent()
7694 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7696 bool hasLengthOrPercentage = false;
7697 bool hasEachLine = false;
7698 bool hasHanging = false;
7700 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7701 // <length> | <percentage> | inherit when RuntimeEnabledFeatures::css3TextEnabled() returns false
7702 if (!hasLengthOrPercentage && validUnit(value, FLength | FPercent)) {
7703 list->append(createPrimitiveNumericValue(value));
7704 hasLengthOrPercentage = true;
7708 // [ <length> | <percentage> ] && hanging? && each-line? | inherit
7709 // when RuntimeEnabledFeatures::css3TextEnabled() returns true
7710 if (RuntimeEnabledFeatures::css3TextEnabled()) {
7711 if (!hasEachLine && value->id == CSSValueEachLine) {
7712 list->append(cssValuePool().createIdentifierValue(CSSValueEachLine));
7716 if (!hasHanging && value->id == CSSValueHanging) {
7717 list->append(cssValuePool().createIdentifierValue(CSSValueHanging));
7725 if (!hasLengthOrPercentage)
7728 return list.release();
7731 bool CSSPropertyParser::parseLineBoxContain(bool important)
7733 LineBoxContain lineBoxContain = LineBoxContainNone;
7735 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7736 if (value->id == CSSValueBlock) {
7737 if (lineBoxContain & LineBoxContainBlock)
7739 lineBoxContain |= LineBoxContainBlock;
7740 } else if (value->id == CSSValueInline) {
7741 if (lineBoxContain & LineBoxContainInline)
7743 lineBoxContain |= LineBoxContainInline;
7744 } else if (value->id == CSSValueFont) {
7745 if (lineBoxContain & LineBoxContainFont)
7747 lineBoxContain |= LineBoxContainFont;
7748 } else if (value->id == CSSValueGlyphs) {
7749 if (lineBoxContain & LineBoxContainGlyphs)
7751 lineBoxContain |= LineBoxContainGlyphs;
7752 } else if (value->id == CSSValueReplaced) {
7753 if (lineBoxContain & LineBoxContainReplaced)
7755 lineBoxContain |= LineBoxContainReplaced;
7756 } else if (value->id == CSSValueInlineBox) {
7757 if (lineBoxContain & LineBoxContainInlineBox)
7759 lineBoxContain |= LineBoxContainInlineBox;
7764 if (!lineBoxContain)
7767 addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
7771 bool CSSPropertyParser::parseFontFeatureTag(CSSValueList* settings)
7773 // Feature tag name consists of 4-letter characters.
7774 static const unsigned tagNameLength = 4;
7776 CSSParserValue* value = m_valueList->current();
7777 // Feature tag name comes first
7778 if (value->unit != CSSPrimitiveValue::CSS_STRING)
7780 if (value->string.length() != tagNameLength)
7782 for (unsigned i = 0; i < tagNameLength; ++i) {
7783 // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
7784 UChar character = value->string[i];
7785 if (character < 0x20 || character > 0x7E)
7789 AtomicString tag = value->string;
7791 // Feature tag values could follow: <integer> | on | off
7792 value = m_valueList->next();
7794 if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
7795 tagValue = clampToInteger(value->fValue);
7798 m_valueList->next();
7799 } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
7800 tagValue = value->id == CSSValueOn;
7801 m_valueList->next();
7804 settings->append(CSSFontFeatureValue::create(tag, tagValue));
7808 bool CSSPropertyParser::parseFontFeatureSettings(bool important)
7810 if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) {
7811 RefPtrWillBeRawPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal);
7812 m_valueList->next();
7813 addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
7817 RefPtrWillBeRawPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
7818 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7819 if (!parseFontFeatureTag(settings.get()))
7822 // If the list isn't parsed fully, the current value should be comma.
7823 value = m_valueList->current();
7824 if (value && !isComma(value))
7827 if (settings->length()) {
7828 addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important);
7834 bool CSSPropertyParser::parseFontVariantLigatures(bool important)
7836 RefPtrWillBeRawPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
7837 bool sawCommonLigaturesValue = false;
7838 bool sawDiscretionaryLigaturesValue = false;
7839 bool sawHistoricalLigaturesValue = false;
7840 bool sawContextualLigaturesValue = false;
7842 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7843 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
7846 switch (value->id) {
7847 case CSSValueNoCommonLigatures:
7848 case CSSValueCommonLigatures:
7849 if (sawCommonLigaturesValue)
7851 sawCommonLigaturesValue = true;
7852 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
7854 case CSSValueNoDiscretionaryLigatures:
7855 case CSSValueDiscretionaryLigatures:
7856 if (sawDiscretionaryLigaturesValue)
7858 sawDiscretionaryLigaturesValue = true;
7859 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
7861 case CSSValueNoHistoricalLigatures:
7862 case CSSValueHistoricalLigatures:
7863 if (sawHistoricalLigaturesValue)
7865 sawHistoricalLigaturesValue = true;
7866 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
7868 case CSSValueNoContextual:
7869 case CSSValueContextual:
7870 if (sawContextualLigaturesValue)
7872 sawContextualLigaturesValue = true;
7873 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
7880 if (!ligatureValues->length())
7883 addProperty(CSSPropertyFontVariantLigatures, ligatureValues.release(), important);
7887 bool CSSPropertyParser::parseCalculation(CSSParserValue* value, ValueRange range)
7889 ASSERT(isCalculation(value));
7891 CSSParserValueList* args = value->function->args.get();
7892 if (!args || !args->size())
7895 ASSERT(!m_parsedCalculation);
7896 m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
7898 if (!m_parsedCalculation)
7904 bool CSSPropertyParser::parseViewportProperty(CSSPropertyID propId, bool important)
7906 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
7908 CSSParserValue* value = m_valueList->current();
7912 CSSValueID id = value->id;
7913 bool validPrimitive = false;
7916 case CSSPropertyMinWidth: // auto | extend-to-zoom | <length> | <percentage>
7917 case CSSPropertyMaxWidth:
7918 case CSSPropertyMinHeight:
7919 case CSSPropertyMaxHeight:
7920 if (id == CSSValueAuto || id == CSSValueInternalExtendToZoom)
7921 validPrimitive = true;
7923 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
7925 case CSSPropertyWidth: // shorthand
7926 return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMaxWidth, important);
7927 case CSSPropertyHeight:
7928 return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyMaxHeight, important);
7929 case CSSPropertyMinZoom: // auto | <number> | <percentage>
7930 case CSSPropertyMaxZoom:
7931 case CSSPropertyZoom:
7932 if (id == CSSValueAuto)
7933 validPrimitive = true;
7935 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg));
7937 case CSSPropertyUserZoom: // zoom | fixed
7938 if (id == CSSValueZoom || id == CSSValueFixed)
7939 validPrimitive = true;
7941 case CSSPropertyOrientation: // auto | portrait | landscape
7942 if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandscape)
7943 validPrimitive = true;
7948 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
7949 if (validPrimitive) {
7950 parsedValue = parseValidPrimitive(id, value);
7951 m_valueList->next();
7955 if (!m_valueList->current() || inShorthand()) {
7956 addProperty(propId, parsedValue.release(), important);
7964 bool CSSPropertyParser::parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first, CSSPropertyID second, bool important)
7966 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
7967 unsigned numValues = m_valueList->size();
7972 ShorthandScope scope(this, propId);
7974 if (!parseViewportProperty(first, important))
7977 // If just one value is supplied, the second value
7978 // is implicitly initialized with the first value.
7980 m_valueList->previous();
7982 return parseViewportProperty(second, important);
7985 template <typename CharacterType>
7986 static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
7988 char buffer[maxCSSPropertyNameLength + 1]; // 1 for null character
7990 for (unsigned i = 0; i != length; ++i) {
7991 CharacterType c = propertyName[i];
7992 if (c == 0 || c >= 0x7F)
7993 return CSSPropertyInvalid; // illegal character
7994 buffer[i] = toASCIILower(c);
7996 buffer[length] = '\0';
7998 const char* name = buffer;
7999 const Property* hashTableEntry = findProperty(name, length);
8000 return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
8003 CSSPropertyID cssPropertyID(const String& string)
8005 unsigned length = string.length();
8008 return CSSPropertyInvalid;
8009 if (length > maxCSSPropertyNameLength)
8010 return CSSPropertyInvalid;
8012 return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
8015 CSSPropertyID cssPropertyID(const CSSParserString& string)
8017 unsigned length = string.length();
8020 return CSSPropertyInvalid;
8021 if (length > maxCSSPropertyNameLength)
8022 return CSSPropertyInvalid;
8024 return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
8027 template <typename CharacterType>
8028 static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
8030 char buffer[maxCSSValueKeywordLength + 1]; // 1 for null character
8032 for (unsigned i = 0; i != length; ++i) {
8033 CharacterType c = valueKeyword[i];
8034 if (c == 0 || c >= 0x7F)
8035 return CSSValueInvalid; // illegal character
8036 buffer[i] = WTF::toASCIILower(c);
8038 buffer[length] = '\0';
8040 const Value* hashTableEntry = findValue(buffer, length);
8041 return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSValueInvalid;
8044 CSSValueID cssValueKeywordID(const CSSParserString& string)
8046 unsigned length = string.length();
8048 return CSSValueInvalid;
8049 if (length > maxCSSValueKeywordLength)
8050 return CSSValueInvalid;
8052 return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
8055 bool isValidNthToken(const CSSParserString& token)
8057 // The tokenizer checks for the construct of an+b.
8058 // However, since the {ident} rule precedes the {nth} rule, some of those
8059 // tokens are identified as string literal. Furthermore we need to accept
8060 // "odd" and "even" which does not match to an+b.
8061 return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
8062 || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");
8065 bool CSSPropertyParser::isSystemColor(int id)
8067 return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu;
8070 bool CSSPropertyParser::parseSVGValue(CSSPropertyID propId, bool important)
8072 CSSParserValue* value = m_valueList->current();
8076 CSSValueID id = value->id;
8078 bool validPrimitive = false;
8079 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
8082 /* The comment to the right defines all valid value of these
8083 * properties as defined in SVG 1.1, Appendix N. Property index */
8084 case CSSPropertyAlignmentBaseline:
8085 // auto | baseline | before-edge | text-before-edge | middle |
8086 // central | after-edge | text-after-edge | ideographic | alphabetic |
8087 // hanging | mathematical | inherit
8088 if (id == CSSValueAuto || id == CSSValueBaseline || id == CSSValueMiddle
8089 || (id >= CSSValueBeforeEdge && id <= CSSValueMathematical))
8090 validPrimitive = true;
8093 case CSSPropertyBaselineShift:
8094 // baseline | super | sub | <percentage> | <length> | inherit
8095 if (id == CSSValueBaseline || id == CSSValueSub
8096 || id >= CSSValueSuper)
8097 validPrimitive = true;
8099 validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
8102 case CSSPropertyDominantBaseline:
8103 // auto | use-script | no-change | reset-size | ideographic |
8104 // alphabetic | hanging | mathematical | central | middle |
8105 // text-after-edge | text-before-edge | inherit
8106 if (id == CSSValueAuto || id == CSSValueMiddle
8107 || (id >= CSSValueUseScript && id <= CSSValueResetSize)
8108 || (id >= CSSValueCentral && id <= CSSValueMathematical))
8109 validPrimitive = true;
8112 case CSSPropertyEnableBackground:
8113 // accumulate | new [x] [y] [width] [height] | inherit
8114 if (id == CSSValueAccumulate) // TODO : new
8115 validPrimitive = true;
8118 case CSSPropertyMarkerStart:
8119 case CSSPropertyMarkerMid:
8120 case CSSPropertyMarkerEnd:
8121 case CSSPropertyMask:
8122 if (id == CSSValueNone) {
8123 validPrimitive = true;
8124 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
8125 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
8127 m_valueList->next();
8131 case CSSPropertyClipRule: // nonzero | evenodd | inherit
8132 case CSSPropertyFillRule:
8133 if (id == CSSValueNonzero || id == CSSValueEvenodd)
8134 validPrimitive = true;
8137 case CSSPropertyStrokeMiterlimit: // <miterlimit> | inherit
8138 validPrimitive = validUnit(value, FNumber | FNonNeg, SVGAttributeMode);
8141 case CSSPropertyStrokeLinejoin: // miter | round | bevel | inherit
8142 if (id == CSSValueMiter || id == CSSValueRound || id == CSSValueBevel)
8143 validPrimitive = true;
8146 case CSSPropertyStrokeLinecap: // butt | round | square | inherit
8147 if (id == CSSValueButt || id == CSSValueRound || id == CSSValueSquare)
8148 validPrimitive = true;
8151 case CSSPropertyStrokeOpacity: // <opacity-value> | inherit
8152 case CSSPropertyFillOpacity:
8153 case CSSPropertyStopOpacity:
8154 case CSSPropertyFloodOpacity:
8155 validPrimitive = (!id && validUnit(value, FNumber | FPercent, SVGAttributeMode));
8158 case CSSPropertyShapeRendering:
8159 // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
8160 if (id == CSSValueAuto || id == CSSValueOptimizespeed
8161 || id == CSSValueCrispedges || id == CSSValueGeometricprecision)
8162 validPrimitive = true;
8165 case CSSPropertyImageRendering: // auto | optimizeSpeed |
8166 case CSSPropertyColorRendering: // optimizeQuality | inherit
8167 if (id == CSSValueAuto || id == CSSValueOptimizespeed
8168 || id == CSSValueOptimizequality)
8169 validPrimitive = true;
8172 case CSSPropertyBufferedRendering: // auto | dynamic | static
8173 if (id == CSSValueAuto || id == CSSValueDynamic || id == CSSValueStatic)
8174 validPrimitive = true;
8177 case CSSPropertyColorInterpolation: // auto | sRGB | linearRGB | inherit
8178 case CSSPropertyColorInterpolationFilters:
8179 if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb)
8180 validPrimitive = true;
8183 /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
8184 * correctly and allows optimization in applyRule(..)
8187 case CSSPropertyTextAnchor: // start | middle | end | inherit
8188 if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd)
8189 validPrimitive = true;
8192 case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit
8193 if (id == CSSValueAuto) {
8194 validPrimitive = true;
8197 /* fallthrough intentional */
8198 case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
8199 if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) {
8200 parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG);
8203 m_valueList->next();
8207 case CSSPropertyFill: // <paint> | inherit
8208 case CSSPropertyStroke: // <paint> | inherit
8210 if (id == CSSValueNone) {
8211 parsedValue = SVGPaint::createNone();
8212 } else if (id == CSSValueCurrentcolor) {
8213 parsedValue = SVGPaint::createCurrentColor();
8214 } else if (isSystemColor(id)) {
8215 parsedValue = SVGPaint::createColor(RenderTheme::theme().systemColor(id));
8216 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
8217 RGBA32 c = Color::transparent;
8218 if (m_valueList->next()) {
8219 if (parseColorFromValue(m_valueList->current(), c))
8220 parsedValue = SVGPaint::createURIAndColor(value->string, c);
8221 else if (m_valueList->current()->id == CSSValueNone)
8222 parsedValue = SVGPaint::createURIAndNone(value->string);
8223 else if (m_valueList->current()->id == CSSValueCurrentcolor)
8224 parsedValue = SVGPaint::createURIAndCurrentColor(value->string);
8227 parsedValue = SVGPaint::createURI(value->string);
8229 parsedValue = parseSVGPaint();
8233 m_valueList->next();
8237 case CSSPropertyStopColor: // TODO : icccolor
8238 case CSSPropertyFloodColor:
8239 case CSSPropertyLightingColor:
8240 if (isSystemColor(id)) {
8241 parsedValue = cssValuePool().createColorValue(RenderTheme::theme().systemColor(id).rgb());
8242 } else if ((id >= CSSValueAqua && id <= CSSValueTransparent)
8243 || (id >= CSSValueAliceblue && id <= CSSValueYellowgreen) || id == CSSValueGrey) {
8244 StyleColor styleColor = SVGPaint::colorFromRGBColorString(value->string);
8245 ASSERT(!styleColor.isCurrentColor());
8246 parsedValue = cssValuePool().createColorValue(styleColor.color().rgb());
8247 } else if (id == CSSValueCurrentcolor) {
8248 parsedValue = cssValuePool().createIdentifierValue(id);
8249 } else { // TODO : svgcolor (iccColor)
8250 parsedValue = parseColor();
8254 m_valueList->next();
8258 case CSSPropertyPaintOrder:
8259 if (m_valueList->size() == 1 && id == CSSValueNormal)
8260 validPrimitive = true;
8261 else if ((parsedValue = parsePaintOrder()))
8262 m_valueList->next();
8265 case CSSPropertyVectorEffect: // none | non-scaling-stroke | inherit
8266 if (id == CSSValueNone || id == CSSValueNonScalingStroke)
8267 validPrimitive = true;
8270 case CSSPropertyWritingMode:
8271 // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
8272 if (id == CSSValueLrTb || id == CSSValueRlTb || id == CSSValueTbRl || id == CSSValueLr || id == CSSValueRl || id == CSSValueTb)
8273 validPrimitive = true;
8276 case CSSPropertyStrokeWidth: // <length> | inherit
8277 case CSSPropertyStrokeDashoffset:
8278 validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
8280 case CSSPropertyStrokeDasharray: // none | <dasharray> | inherit
8281 if (id == CSSValueNone)
8282 validPrimitive = true;
8284 parsedValue = parseSVGStrokeDasharray();
8288 case CSSPropertyClipPath: // <uri> | none | inherit
8289 case CSSPropertyFilter:
8290 if (id == CSSValueNone) {
8291 validPrimitive = true;
8292 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
8293 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitType) value->unit);
8295 m_valueList->next();
8298 case CSSPropertyMaskType: // luminance | alpha | inherit
8299 if (id == CSSValueLuminance || id == CSSValueAlpha)
8300 validPrimitive = true;
8303 /* shorthand properties */
8304 case CSSPropertyMarker: {
8305 ShorthandScope scope(this, propId);
8306 CSSPropertyParser::ImplicitScope implicitScope(this, PropertyImplicit);
8307 if (!parseValue(CSSPropertyMarkerStart, important))
8309 if (m_valueList->current()) {
8310 rollbackLastProperties(1);
8313 CSSValue* value = m_parsedProperties.last().value();
8314 addProperty(CSSPropertyMarkerMid, value, important);
8315 addProperty(CSSPropertyMarkerEnd, value, important);
8319 // If you crash here, it's because you added a css property and are not handling it
8320 // in either this switch statement or the one in CSSPropertyParser::parseValue
8321 ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
8325 if (validPrimitive) {
8327 parsedValue = CSSPrimitiveValue::createIdentifier(id);
8328 else if (value->unit == CSSPrimitiveValue::CSS_STRING)
8329 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitType) value->unit);
8330 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
8331 parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitType) value->unit);
8332 else if (value->unit >= CSSParserValue::Q_EMS)
8333 parsedValue = CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
8334 if (isCalculation(value)) {
8335 // FIXME calc() http://webkit.org/b/16662 : actually create a CSSPrimitiveValue here, ie
8336 // parsedValue = CSSPrimitiveValue::create(m_parsedCalculation.release());
8337 m_parsedCalculation.release();
8338 parsedValue = nullptr;
8340 m_valueList->next();
8342 if (!parsedValue || (m_valueList->current() && !inShorthand()))
8345 addProperty(propId, parsedValue.release(), important);
8349 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGStrokeDasharray()
8351 RefPtrWillBeRawPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
8352 CSSParserValue* value = m_valueList->current();
8353 bool validPrimitive = true;
8355 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttributeMode);
8356 if (!validPrimitive)
8359 ret->append(CSSPrimitiveValue::createIdentifier(value->id));
8360 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
8361 ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitType) value->unit));
8362 value = m_valueList->next();
8363 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
8364 value = m_valueList->next();
8366 if (!validPrimitive)
8368 return ret.release();
8371 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGPaint()
8373 RGBA32 c = Color::transparent;
8374 if (!parseColorFromValue(m_valueList->current(), c))
8375 return SVGPaint::createUnknown();
8376 return SVGPaint::createColor(Color(c));
8379 // normal | [ fill || stroke || markers ]
8380 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parsePaintOrder() const
8382 if (m_valueList->size() > 3)
8385 CSSParserValue* value = m_valueList->current();
8389 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
8391 // The default paint-order is: Fill, Stroke, Markers.
8392 bool seenFill = false, seenStroke = false, seenMarkers = false;
8395 switch (value->id) {
8396 case CSSValueNormal:
8397 // normal inside [fill || stroke || markers] not valid
8405 case CSSValueStroke:
8411 case CSSValueMarkers:
8421 parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id));
8422 } while ((value = m_valueList->next()));
8424 // fill out the rest of the paint order
8426 parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueFill));
8428 parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueStroke));
8430 parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueMarkers));
8432 return parsedValues.release();
8435 } // namespace WebCore