2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
6 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
7 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
9 * Copyright (C) 2012 Intel Corporation. All rights reserved.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
28 #include "core/css/parser/CSSPropertyParser.h"
29 #include "RuntimeEnabledFeatures.h"
30 #include "core/rendering/RenderTheme.h"
31 #include "core/svg/SVGPaint.h"
32 // FIXME: Way too many!
33 #include "CSSValueKeywords.h"
34 #include "RuntimeEnabledFeatures.h"
35 #include "StylePropertyShorthand.h"
36 #include "core/css/CSSArrayFunctionValue.h"
37 #include "core/css/CSSAspectRatioValue.h"
38 #include "core/css/CSSBasicShapes.h"
39 #include "core/css/CSSBorderImage.h"
40 #include "core/css/CSSCanvasValue.h"
41 #include "core/css/CSSCrossfadeValue.h"
42 #include "core/css/CSSCursorImageValue.h"
43 #include "core/css/CSSFontFaceSrcValue.h"
44 #include "core/css/CSSFontFeatureValue.h"
45 #include "core/css/CSSFunctionValue.h"
46 #include "core/css/CSSGradientValue.h"
47 #include "core/css/CSSGridLineNamesValue.h"
48 #include "core/css/CSSGridTemplateAreasValue.h"
49 #include "core/css/CSSImageSetValue.h"
50 #include "core/css/CSSImageValue.h"
51 #include "core/css/CSSInheritedValue.h"
52 #include "core/css/CSSInitialValue.h"
53 #include "core/css/CSSKeyframeRule.h"
54 #include "core/css/CSSKeyframesRule.h"
55 #include "core/css/CSSLineBoxContainValue.h"
56 #include "core/css/CSSParserValues.h"
57 #include "core/css/CSSPrimitiveValue.h"
58 #include "core/css/CSSPropertySourceData.h"
59 #include "core/css/CSSReflectValue.h"
60 #include "core/css/CSSSVGDocumentValue.h"
61 #include "core/css/CSSSelector.h"
62 #include "core/css/CSSShadowValue.h"
63 #include "core/css/CSSTimingFunctionValue.h"
64 #include "core/css/CSSTransformValue.h"
65 #include "core/css/CSSUnicodeRangeValue.h"
66 #include "core/css/CSSValueList.h"
67 #include "core/css/CSSValuePool.h"
68 #include "core/css/Counter.h"
69 #include "core/css/HashTools.h"
70 #include "core/css/Pair.h"
71 #include "core/css/Rect.h"
72 #include "core/css/RuntimeCSSEnabled.h"
73 #include "core/css/parser/CSSParserIdioms.h"
74 #include "core/html/parser/HTMLParserIdioms.h"
75 #include "core/inspector/InspectorInstrumentation.h"
76 #include "core/rendering/RenderTheme.h"
77 #include "core/svg/SVGParserUtilities.h"
78 #include "platform/FloatConversion.h"
79 #include "wtf/BitArray.h"
80 #include "wtf/HexNumber.h"
81 #include "wtf/text/StringBuffer.h"
82 #include "wtf/text/StringBuilder.h"
83 #include "wtf/text/StringImpl.h"
84 #include "wtf/text/TextEncoding.h"
91 static const double MAX_SCALE = 1000000;
94 static bool equal(const CSSParserString& a, const char (&b)[N])
96 unsigned length = N - 1; // Ignore the trailing null character
97 if (a.length() != length)
100 return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar*>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length);
103 template <unsigned N>
104 static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
106 unsigned length = N - 1; // Ignore the trailing null character
107 if (a.length() != length)
110 return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length);
113 template <unsigned N>
114 static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N])
116 ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrimitiveValue::CSS_STRING);
117 return equalIgnoringCase(value->string, b);
120 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> first, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> second, Pair::IdenticalValuesPolicy identicalValuesPolicy = Pair::DropIdenticalValues)
122 return cssValuePool().createValue(Pair::create(first, second, identicalValuesPolicy));
125 class AnimationParseContext {
127 AnimationParseContext()
128 : m_animationPropertyKeywordAllowed(true)
129 , m_firstAnimationCommitted(false)
130 , m_hasSeenAnimationPropertyKeyword(false)
134 void commitFirstAnimation()
136 m_firstAnimationCommitted = true;
139 bool hasCommittedFirstAnimation() const
141 return m_firstAnimationCommitted;
144 void commitAnimationPropertyKeyword()
146 m_animationPropertyKeywordAllowed = false;
149 bool animationPropertyKeywordAllowed() const
151 return m_animationPropertyKeywordAllowed;
154 bool hasSeenAnimationPropertyKeyword() const
156 return m_hasSeenAnimationPropertyKeyword;
159 void sawAnimationPropertyKeyword()
161 m_hasSeenAnimationPropertyKeyword = true;
165 bool m_animationPropertyKeywordAllowed;
166 bool m_firstAnimationCommitted;
167 bool m_hasSeenAnimationPropertyKeyword;
170 CSSPropertyParser::CSSPropertyParser(OwnPtr<CSSParserValueList>& valueList,
171 const CSSParserContext& context, bool inViewport, bool savedImportant,
172 WillBeHeapVector<CSSProperty, 256>& parsedProperties, bool& hasFontFaceOnlyValues)
173 : m_valueList(valueList)
175 , m_inViewport(inViewport)
176 , m_important(savedImportant) // See comment in header, should be removed.
177 , m_parsedProperties(parsedProperties)
178 , m_hasFontFaceOnlyValues(hasFontFaceOnlyValues)
179 , m_inParseShorthand(0)
180 , m_currentShorthand(CSSPropertyInvalid)
181 , m_implicitShorthand(false)
185 CSSPropertyParser::~CSSPropertyParser()
189 void CSSPropertyParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important, bool implicit)
191 RefPtrWillBeRawPtr<CSSValue> val = value.get();
192 addProperty(propId, value, important, implicit);
194 CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId);
195 if (prefixingVariant == propId)
198 if (m_currentShorthand) {
199 // We can't use ShorthandScope here as we can already be inside one (e.g we are parsing CSSTransition).
200 m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
201 addProperty(prefixingVariant, val.release(), important, implicit);
202 m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
204 addProperty(prefixingVariant, val.release(), important, implicit);
208 void CSSPropertyParser::addProperty(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important, bool implicit)
210 // This property doesn't belong to a shorthand.
211 if (!m_currentShorthand) {
212 m_parsedProperties.append(CSSProperty(propId, value, important, false, CSSPropertyInvalid, m_implicitShorthand || implicit));
216 Vector<StylePropertyShorthand, 4> shorthands;
217 getMatchingShorthandsForLonghand(propId, &shorthands);
218 // The longhand does not belong to multiple shorthands.
219 if (shorthands.size() == 1)
220 m_parsedProperties.append(CSSProperty(propId, value, important, true, CSSPropertyInvalid, m_implicitShorthand || implicit));
222 m_parsedProperties.append(CSSProperty(propId, value, important, true, indexOfShorthandForLonghand(m_currentShorthand, shorthands), m_implicitShorthand || implicit));
225 void CSSPropertyParser::rollbackLastProperties(int num)
228 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
229 m_parsedProperties.shrink(m_parsedProperties.size() - num);
232 KURL CSSPropertyParser::completeURL(const String& url) const
234 return m_context.completeURL(url);
237 bool CSSPropertyParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc)
239 bool mustBeNonNegative = unitflags & FNonNeg;
241 if (!parseCalculation(value, mustBeNonNegative ? ValueRangeNonNegative : ValueRangeAll))
245 switch (m_parsedCalculation->category()) {
247 b = (unitflags & FLength);
250 b = (unitflags & FPercent);
251 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
255 b = (unitflags & FNumber);
256 if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
258 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
261 case CalcPercentLength:
262 b = (unitflags & FPercent) && (unitflags & FLength);
264 case CalcPercentNumber:
265 b = (unitflags & FPercent) && (unitflags & FNumber);
270 if (!b || releaseCalc == ReleaseParsedCalcValue)
271 m_parsedCalculation.release();
275 inline bool CSSPropertyParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
277 // Quirks mode and presentation attributes accept unit less values.
278 return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || isUnitLessLengthParsingEnabledForMode(cssParserMode));
281 bool CSSPropertyParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
283 if (isCalculation(value))
284 return validCalculationUnit(value, unitflags, releaseCalc);
287 switch (value->unit) {
288 case CSSPrimitiveValue::CSS_NUMBER:
289 b = (unitflags & FNumber);
290 if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
291 value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
292 ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
295 if (!b && (unitflags & FInteger) && value->isInt)
297 if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0)
300 case CSSPrimitiveValue::CSS_PERCENTAGE:
301 b = (unitflags & FPercent);
303 case CSSParserValue::Q_EMS:
304 case CSSPrimitiveValue::CSS_EMS:
305 case CSSPrimitiveValue::CSS_REMS:
306 case CSSPrimitiveValue::CSS_CHS:
307 case CSSPrimitiveValue::CSS_EXS:
308 case CSSPrimitiveValue::CSS_PX:
309 case CSSPrimitiveValue::CSS_CM:
310 case CSSPrimitiveValue::CSS_MM:
311 case CSSPrimitiveValue::CSS_IN:
312 case CSSPrimitiveValue::CSS_PT:
313 case CSSPrimitiveValue::CSS_PC:
314 case CSSPrimitiveValue::CSS_VW:
315 case CSSPrimitiveValue::CSS_VH:
316 case CSSPrimitiveValue::CSS_VMIN:
317 case CSSPrimitiveValue::CSS_VMAX:
318 b = (unitflags & FLength);
320 case CSSPrimitiveValue::CSS_MS:
321 case CSSPrimitiveValue::CSS_S:
322 b = (unitflags & FTime);
324 case CSSPrimitiveValue::CSS_DEG:
325 case CSSPrimitiveValue::CSS_RAD:
326 case CSSPrimitiveValue::CSS_GRAD:
327 case CSSPrimitiveValue::CSS_TURN:
328 b = (unitflags & FAngle);
330 case CSSPrimitiveValue::CSS_DPPX:
331 case CSSPrimitiveValue::CSS_DPI:
332 case CSSPrimitiveValue::CSS_DPCM:
333 b = (unitflags & FResolution);
335 case CSSPrimitiveValue::CSS_HZ:
336 case CSSPrimitiveValue::CSS_KHZ:
337 case CSSPrimitiveValue::CSS_DIMENSION:
341 if (b && unitflags & FNonNeg && value->fValue < 0)
346 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimitiveNumericValue(CSSParserValue* value)
348 if (m_parsedCalculation) {
349 ASSERT(isCalculation(value));
350 return CSSPrimitiveValue::create(m_parsedCalculation.release());
353 ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
354 || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
355 || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
356 || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
357 return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
360 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimitiveStringValue(CSSParserValue* value)
362 ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
363 return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
366 static inline bool isComma(CSSParserValue* value)
368 return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
371 static inline bool isForwardSlashOperator(CSSParserValue* value)
374 return value->unit == CSSParserValue::Operator && value->iValue == '/';
377 static bool isGeneratedImageValue(CSSParserValue* val)
379 if (val->unit != CSSParserValue::Function)
382 return equalIgnoringCase(val->function->name, "-webkit-gradient(")
383 || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
384 || equalIgnoringCase(val->function->name, "linear-gradient(")
385 || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
386 || equalIgnoringCase(val->function->name, "repeating-linear-gradient(")
387 || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
388 || equalIgnoringCase(val->function->name, "radial-gradient(")
389 || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
390 || equalIgnoringCase(val->function->name, "repeating-radial-gradient(")
391 || equalIgnoringCase(val->function->name, "-webkit-canvas(")
392 || equalIgnoringCase(val->function->name, "-webkit-cross-fade(");
395 bool CSSPropertyParser::validWidthOrHeight(CSSParserValue* value)
398 if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
400 return !id && validUnit(value, FLength | FPercent | FNonNeg);
403 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value)
406 return cssValuePool().createIdentifierValue(identifier);
407 if (value->unit == CSSPrimitiveValue::CSS_STRING)
408 return createPrimitiveStringValue(value);
409 if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
410 return createPrimitiveNumericValue(value);
411 if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
412 return createPrimitiveNumericValue(value);
413 if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
414 return createPrimitiveNumericValue(value);
415 if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
416 return createPrimitiveNumericValue(value);
417 if (value->unit >= CSSParserValue::Q_EMS)
418 return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
419 if (isCalculation(value))
420 return CSSPrimitiveValue::create(m_parsedCalculation.release());
425 void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> prpValue, bool important)
427 const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
428 unsigned shorthandLength = shorthand.length();
429 if (!shorthandLength) {
430 addProperty(propId, prpValue, important);
434 RefPtrWillBeRawPtr<CSSValue> value = prpValue;
435 ShorthandScope scope(this, propId);
436 const CSSPropertyID* longhands = shorthand.properties();
437 for (unsigned i = 0; i < shorthandLength; ++i)
438 addProperty(longhands[i], value, important);
441 bool CSSPropertyParser::parseValue(CSSPropertyID propId, bool important)
443 if (!isInternalPropertyAndValueParsingEnabledForMode(m_context.mode()) && isInternalProperty(propId))
446 // We don't count the UA style sheet in our statistics.
447 if (m_context.useCounter())
448 m_context.useCounter()->count(m_context, propId);
453 CSSParserValue* value = m_valueList->current();
459 // Allow @viewport rules from UA stylesheets even if the feature is disabled.
460 if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode()))
463 return parseViewportProperty(propId, important);
466 // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
467 // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
468 ASSERT(!m_parsedCalculation);
470 CSSValueID id = value->id;
472 int num = inShorthand() ? 1 : m_valueList->size();
474 if (id == CSSValueInherit) {
477 addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important);
480 else if (id == CSSValueInitial) {
483 addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important);
487 if (isKeywordPropertyID(propId)) {
488 if (!isValidKeywordPropertyAndValue(propId, id, m_context))
490 if (m_valueList->next() && !inShorthand())
492 addProperty(propId, cssValuePool().createIdentifierValue(id), important);
496 bool validPrimitive = false;
497 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
500 case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
501 return parseSize(propId, important);
503 case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit
505 validPrimitive = true;
507 return parseQuotes(propId, important);
509 case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | isolate-override | plaintext | inherit
510 if (id == CSSValueNormal
511 || id == CSSValueEmbed
512 || id == CSSValueBidiOverride
513 || id == CSSValueWebkitIsolate
514 || id == CSSValueWebkitIsolateOverride
515 || id == CSSValueWebkitPlaintext)
516 validPrimitive = true;
519 case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
520 // close-quote | no-open-quote | no-close-quote ]+ | inherit
521 return parseContent(propId, important);
523 case CSSPropertyClip: // <shape> | auto | inherit
524 if (id == CSSValueAuto)
525 validPrimitive = true;
526 else if (value->unit == CSSParserValue::Function)
527 return parseClipShape(propId, important);
530 /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
531 * correctly and allows optimization in WebCore::applyRule(..)
533 case CSSPropertyOverflow: {
534 ShorthandScope scope(this, propId);
535 if (num != 1 || !parseValue(CSSPropertyOverflowY, important))
538 RefPtrWillBeRawPtr<CSSValue> overflowXValue = nullptr;
540 // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been
541 // set using the shorthand, then for now overflow-x will default to auto, but once we implement
542 // pagination controls, it should default to hidden. If the overflow-y value is anything but
543 // paged-x or paged-y, then overflow-x and overflow-y should have the same value.
544 if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
545 overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
547 overflowXValue = m_parsedProperties.last().value();
548 addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
552 case CSSPropertyTextAlign:
553 // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
554 // | start | end | <string> | inherit | -webkit-auto (converted to start)
555 if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
556 || value->unit == CSSPrimitiveValue::CSS_STRING)
557 validPrimitive = true;
560 case CSSPropertyFontWeight: { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
561 if (m_valueList->size() != 1)
563 return parseFontWeight(important);
565 case CSSPropertyBorderSpacing: {
567 ShorthandScope scope(this, CSSPropertyBorderSpacing);
568 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
570 CSSValue* value = m_parsedProperties.last().value();
571 addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
575 ShorthandScope scope(this, CSSPropertyBorderSpacing);
576 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
582 case CSSPropertyWebkitBorderHorizontalSpacing:
583 case CSSPropertyWebkitBorderVerticalSpacing:
584 validPrimitive = validUnit(value, FLength | FNonNeg);
586 case CSSPropertyOutlineColor: // <color> | invert | inherit
587 // Outline color has "invert" as additional keyword.
588 // Also, we want to allow the special focus color even in HTML Standard parsing mode.
589 if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
590 validPrimitive = true;
594 case CSSPropertyBackgroundColor: // <color> | inherit
595 case CSSPropertyBorderTopColor: // <color> | inherit
596 case CSSPropertyBorderRightColor:
597 case CSSPropertyBorderBottomColor:
598 case CSSPropertyBorderLeftColor:
599 case CSSPropertyWebkitBorderStartColor:
600 case CSSPropertyWebkitBorderEndColor:
601 case CSSPropertyWebkitBorderBeforeColor:
602 case CSSPropertyWebkitBorderAfterColor:
603 case CSSPropertyColor: // <color> | inherit
604 case CSSPropertyTextDecorationColor: // CSS3 text decoration colors
605 case CSSPropertyTextLineThroughColor:
606 case CSSPropertyTextUnderlineColor:
607 case CSSPropertyTextOverlineColor:
608 case CSSPropertyWebkitColumnRuleColor:
609 case CSSPropertyWebkitTextEmphasisColor:
610 case CSSPropertyWebkitTextFillColor:
611 case CSSPropertyWebkitTextStrokeColor:
612 if (propId == CSSPropertyTextDecorationColor
613 && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
616 if ((id >= CSSValueAqua && id <= CSSValueWebkitText) || id == CSSValueMenu) {
617 validPrimitive = isValueAllowedInMode(id, m_context.mode());
619 parsedValue = parseColor();
625 case CSSPropertyCursor: {
626 // Grammar defined by CSS3 UI and modified by CSS4 images:
627 // [ [<image> [<x> <y>]?,]*
628 // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
629 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
630 // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
631 // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
632 // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
633 RefPtrWillBeRawPtr<CSSValueList> list = nullptr;
635 RefPtrWillBeRawPtr<CSSValue> image = nullptr;
636 if (value->unit == CSSPrimitiveValue::CSS_URI) {
637 String uri = value->string;
639 image = CSSImageValue::create(uri, completeURL(uri));
640 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
641 image = parseImageSet(m_valueList.get());
648 value = m_valueList->next();
649 while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
650 coords.append(int(value->fValue));
651 value = m_valueList->next();
653 bool hasHotSpot = false;
654 IntPoint hotSpot(-1, -1);
655 int nrcoords = coords.size();
656 if (nrcoords > 0 && nrcoords != 2)
660 hotSpot = IntPoint(coords[0], coords[1]);
664 list = CSSValueList::createCommaSeparated();
667 list->append(CSSCursorImageValue::create(image, hasHotSpot, hotSpot));
669 if (!value || !(value->unit == CSSParserValue::Operator && value->iValue == ','))
671 value = m_valueList->next(); // comma
676 if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
677 list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
678 else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
679 list->append(cssValuePool().createIdentifierValue(value->id));
681 parsedValue = list.release();
685 if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
686 id = CSSValuePointer;
687 validPrimitive = true;
688 } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
689 validPrimitive = true;
691 ASSERT_NOT_REACHED();
697 case CSSPropertyBackgroundBlendMode:
698 case CSSPropertyBackgroundAttachment:
699 case CSSPropertyBackgroundClip:
700 case CSSPropertyWebkitBackgroundClip:
701 case CSSPropertyWebkitBackgroundComposite:
702 case CSSPropertyBackgroundImage:
703 case CSSPropertyBackgroundOrigin:
704 case CSSPropertyMaskSourceType:
705 case CSSPropertyWebkitBackgroundOrigin:
706 case CSSPropertyBackgroundPosition:
707 case CSSPropertyBackgroundPositionX:
708 case CSSPropertyBackgroundPositionY:
709 case CSSPropertyBackgroundSize:
710 case CSSPropertyWebkitBackgroundSize:
711 case CSSPropertyBackgroundRepeat:
712 case CSSPropertyBackgroundRepeatX:
713 case CSSPropertyBackgroundRepeatY:
714 case CSSPropertyWebkitMaskClip:
715 case CSSPropertyWebkitMaskComposite:
716 case CSSPropertyWebkitMaskImage:
717 case CSSPropertyWebkitMaskOrigin:
718 case CSSPropertyWebkitMaskPosition:
719 case CSSPropertyWebkitMaskPositionX:
720 case CSSPropertyWebkitMaskPositionY:
721 case CSSPropertyWebkitMaskSize:
722 case CSSPropertyWebkitMaskRepeat:
723 case CSSPropertyWebkitMaskRepeatX:
724 case CSSPropertyWebkitMaskRepeatY:
726 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
727 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
728 CSSPropertyID propId1, propId2;
730 if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
731 if (propId == CSSPropertyBackgroundPosition ||
732 propId == CSSPropertyBackgroundRepeat ||
733 propId == CSSPropertyWebkitMaskPosition ||
734 propId == CSSPropertyWebkitMaskRepeat) {
735 ShorthandScope scope(this, propId);
736 addProperty(propId1, val1.release(), important);
738 addProperty(propId2, val2.release(), important);
740 addProperty(propId1, val1.release(), important);
742 addProperty(propId2, val2.release(), important);
746 m_implicitShorthand = false;
749 case CSSPropertyObjectPosition:
750 return RuntimeEnabledFeatures::objectFitPositionEnabled() && parseObjectPosition(important);
751 case CSSPropertyListStyleImage: // <uri> | none | inherit
752 case CSSPropertyBorderImageSource:
753 case CSSPropertyWebkitMaskBoxImageSource:
754 if (id == CSSValueNone) {
755 parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
757 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
758 parsedValue = CSSImageValue::create(value->string, completeURL(value->string));
760 } else if (isGeneratedImageValue(value)) {
761 if (parseGeneratedImage(m_valueList.get(), parsedValue))
766 else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
767 parsedValue = parseImageSet(m_valueList.get());
774 case CSSPropertyWebkitTextStrokeWidth:
775 case CSSPropertyOutlineWidth: // <border-width> | inherit
776 case CSSPropertyBorderTopWidth: //// <border-width> | inherit
777 case CSSPropertyBorderRightWidth: // Which is defined as
778 case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
779 case CSSPropertyBorderLeftWidth:
780 case CSSPropertyWebkitBorderStartWidth:
781 case CSSPropertyWebkitBorderEndWidth:
782 case CSSPropertyWebkitBorderBeforeWidth:
783 case CSSPropertyWebkitBorderAfterWidth:
784 case CSSPropertyWebkitColumnRuleWidth:
785 if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
786 validPrimitive = true;
788 validPrimitive = validUnit(value, FLength | FNonNeg);
791 case CSSPropertyLetterSpacing: // normal | <length> | inherit
792 case CSSPropertyWordSpacing: // normal | <length> | inherit
793 if (id == CSSValueNormal)
794 validPrimitive = true;
796 validPrimitive = validUnit(value, FLength);
799 case CSSPropertyTextIndent:
800 parsedValue = parseTextIndent();
803 case CSSPropertyPaddingTop: //// <padding-width> | inherit
804 case CSSPropertyPaddingRight: // Which is defined as
805 case CSSPropertyPaddingBottom: // <length> | <percentage>
806 case CSSPropertyPaddingLeft: ////
807 case CSSPropertyWebkitPaddingStart:
808 case CSSPropertyWebkitPaddingEnd:
809 case CSSPropertyWebkitPaddingBefore:
810 case CSSPropertyWebkitPaddingAfter:
811 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
814 case CSSPropertyMaxWidth:
815 case CSSPropertyWebkitMaxLogicalWidth:
816 case CSSPropertyMaxHeight:
817 case CSSPropertyWebkitMaxLogicalHeight:
818 validPrimitive = (id == CSSValueNone || validWidthOrHeight(value));
821 case CSSPropertyMinWidth:
822 case CSSPropertyWebkitMinLogicalWidth:
823 case CSSPropertyMinHeight:
824 case CSSPropertyWebkitMinLogicalHeight:
825 validPrimitive = validWidthOrHeight(value);
828 case CSSPropertyWidth:
829 case CSSPropertyWebkitLogicalWidth:
830 case CSSPropertyHeight:
831 case CSSPropertyWebkitLogicalHeight:
832 validPrimitive = (id == CSSValueAuto || validWidthOrHeight(value));
835 case CSSPropertyFontSize:
836 return parseFontSize(important);
838 case CSSPropertyFontVariant: // normal | small-caps | inherit
839 return parseFontVariant(important);
841 case CSSPropertyVerticalAlign:
842 // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
843 // <percentage> | <length> | inherit
845 if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
846 validPrimitive = true;
848 validPrimitive = (!id && validUnit(value, FLength | FPercent));
851 case CSSPropertyBottom: // <length> | <percentage> | auto | inherit
852 case CSSPropertyLeft: // <length> | <percentage> | auto | inherit
853 case CSSPropertyRight: // <length> | <percentage> | auto | inherit
854 case CSSPropertyTop: // <length> | <percentage> | auto | inherit
855 case CSSPropertyMarginTop: //// <margin-width> | inherit
856 case CSSPropertyMarginRight: // Which is defined as
857 case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit
858 case CSSPropertyMarginLeft: ////
859 case CSSPropertyWebkitMarginStart:
860 case CSSPropertyWebkitMarginEnd:
861 case CSSPropertyWebkitMarginBefore:
862 case CSSPropertyWebkitMarginAfter:
863 if (id == CSSValueAuto)
864 validPrimitive = true;
866 validPrimitive = (!id && validUnit(value, FLength | FPercent));
869 case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
870 case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
871 if (id == CSSValueAuto)
872 validPrimitive = true;
874 validPrimitive = (!id && validUnit(value, FPositiveInteger, HTMLQuirksMode));
877 case CSSPropertyZIndex: // auto | <integer> | inherit
878 if (id == CSSValueAuto)
879 validPrimitive = true;
881 validPrimitive = (!id && validUnit(value, FInteger, HTMLQuirksMode));
884 case CSSPropertyLineHeight:
885 return parseLineHeight(important);
886 case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
887 if (id != CSSValueNone)
888 return parseCounter(propId, 1, important);
889 validPrimitive = true;
891 case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit
892 if (id != CSSValueNone)
893 return parseCounter(propId, 0, important);
894 validPrimitive = true;
896 case CSSPropertyFontFamily:
897 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
899 parsedValue = parseFontFamily();
903 case CSSPropertyTextDecoration:
904 // Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration
905 // is disabled to match CSS 2.1 rules for parsing 'text-decoration'.
906 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) {
907 // [ <text-decoration-line> || <text-decoration-style> || <text-decoration-color> ] | inherit
908 return parseShorthand(CSSPropertyTextDecoration, textDecorationShorthand(), important);
910 case CSSPropertyWebkitTextDecorationsInEffect:
911 case CSSPropertyTextDecorationLine:
912 // none | [ underline || overline || line-through || blink ] | inherit
913 return parseTextDecoration(propId, important);
915 case CSSPropertyTextDecorationStyle:
916 // solid | double | dotted | dashed | wavy
917 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()
918 && (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDotted || id == CSSValueDashed || id == CSSValueWavy))
919 validPrimitive = true;
922 case CSSPropertyTextUnderlinePosition:
923 // auto | under | inherit
924 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled())
925 return parseTextUnderlinePosition(important);
928 case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit
929 if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
930 validPrimitive = true;
932 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode));
935 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.
936 return parseFontFaceSrc();
938 case CSSPropertyUnicodeRange:
939 return parseFontFaceUnicodeRange();
941 /* CSS3 properties */
943 case CSSPropertyBorderImage:
944 case CSSPropertyWebkitMaskBoxImage:
945 return parseBorderImageShorthand(propId, important);
946 case CSSPropertyWebkitBorderImage: {
947 if (RefPtrWillBeRawPtr<CSSValue> result = parseBorderImage(propId)) {
948 addProperty(propId, result, important);
954 case CSSPropertyBorderImageOutset:
955 case CSSPropertyWebkitMaskBoxImageOutset: {
956 RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
957 if (parseBorderImageOutset(result)) {
958 addProperty(propId, result, important);
963 case CSSPropertyBorderImageRepeat:
964 case CSSPropertyWebkitMaskBoxImageRepeat: {
965 RefPtrWillBeRawPtr<CSSValue> result = nullptr;
966 if (parseBorderImageRepeat(result)) {
967 addProperty(propId, result, important);
972 case CSSPropertyBorderImageSlice:
973 case CSSPropertyWebkitMaskBoxImageSlice: {
974 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> result = nullptr;
975 if (parseBorderImageSlice(propId, result)) {
976 addProperty(propId, result, important);
981 case CSSPropertyBorderImageWidth:
982 case CSSPropertyWebkitMaskBoxImageWidth: {
983 RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
984 if (parseBorderImageWidth(result)) {
985 addProperty(propId, result, important);
990 case CSSPropertyBorderTopRightRadius:
991 case CSSPropertyBorderTopLeftRadius:
992 case CSSPropertyBorderBottomLeftRadius:
993 case CSSPropertyBorderBottomRightRadius: {
994 if (num != 1 && num != 2)
996 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
999 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
1000 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr;
1002 value = m_valueList->next();
1003 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
1004 if (!validPrimitive)
1006 parsedValue2 = createPrimitiveNumericValue(value);
1008 parsedValue2 = parsedValue1;
1010 addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important);
1013 case CSSPropertyTabSize:
1014 validPrimitive = validUnit(value, FInteger | FNonNeg);
1016 case CSSPropertyWebkitAspectRatio:
1017 return parseAspectRatio(important);
1018 case CSSPropertyBorderRadius:
1019 case CSSPropertyWebkitBorderRadius:
1020 return parseBorderRadius(propId, important);
1021 case CSSPropertyOutlineOffset:
1022 validPrimitive = validUnit(value, FLength);
1024 case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
1025 case CSSPropertyBoxShadow:
1026 case CSSPropertyWebkitBoxShadow:
1027 if (id == CSSValueNone)
1028 validPrimitive = true;
1030 RefPtrWillBeRawPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
1031 if (shadowValueList) {
1032 addProperty(propId, shadowValueList.release(), important);
1033 m_valueList->next();
1039 case CSSPropertyWebkitBoxReflect:
1040 if (id == CSSValueNone)
1041 validPrimitive = true;
1043 return parseReflect(propId, important);
1045 case CSSPropertyOpacity:
1046 validPrimitive = validUnit(value, FNumber);
1048 case CSSPropertyWebkitBoxFlex:
1049 validPrimitive = validUnit(value, FNumber);
1051 case CSSPropertyWebkitBoxFlexGroup:
1052 validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode);
1054 case CSSPropertyWebkitBoxOrdinalGroup:
1055 validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode) && value->fValue;
1057 case CSSPropertyWebkitFilter:
1058 if (id == CSSValueNone)
1059 validPrimitive = true;
1061 RefPtrWillBeRawPtr<CSSValue> val = parseFilter();
1063 addProperty(propId, val, important);
1069 case CSSPropertyFlex: {
1070 ShorthandScope scope(this, propId);
1071 if (id == CSSValueNone) {
1072 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
1073 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
1074 addProperty(CSSPropertyFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
1077 return parseFlex(m_valueList.get(), important);
1079 case CSSPropertyFlexBasis:
1080 // FIXME: Support intrinsic dimensions too.
1081 if (id == CSSValueAuto)
1082 validPrimitive = true;
1084 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
1086 case CSSPropertyFlexGrow:
1087 case CSSPropertyFlexShrink:
1088 validPrimitive = validUnit(value, FNumber | FNonNeg);
1090 case CSSPropertyOrder:
1091 validPrimitive = validUnit(value, FInteger, HTMLStandardMode);
1093 case CSSPropertyInternalMarqueeIncrement:
1094 if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
1095 validPrimitive = true;
1097 validPrimitive = validUnit(value, FLength | FPercent);
1099 case CSSPropertyInternalMarqueeRepetition:
1100 if (id == CSSValueInfinite)
1101 validPrimitive = true;
1103 validPrimitive = validUnit(value, FInteger | FNonNeg);
1105 case CSSPropertyInternalMarqueeSpeed:
1106 if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
1107 validPrimitive = true;
1109 validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
1111 case CSSPropertyWebkitTransform:
1112 if (id == CSSValueNone)
1113 validPrimitive = true;
1115 RefPtrWillBeRawPtr<CSSValue> transformValue = parseTransform();
1116 if (transformValue) {
1117 addProperty(propId, transformValue.release(), important);
1123 case CSSPropertyWebkitTransformOrigin:
1124 case CSSPropertyWebkitTransformOriginX:
1125 case CSSPropertyWebkitTransformOriginY:
1126 case CSSPropertyWebkitTransformOriginZ: {
1127 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
1128 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
1129 RefPtrWillBeRawPtr<CSSValue> val3 = nullptr;
1130 CSSPropertyID propId1, propId2, propId3;
1131 if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
1132 addProperty(propId1, val1.release(), important);
1134 addProperty(propId2, val2.release(), important);
1136 addProperty(propId3, val3.release(), important);
1141 case CSSPropertyWebkitPerspective:
1142 if (id == CSSValueNone)
1143 validPrimitive = true;
1145 // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
1146 if (validUnit(value, FNumber | FLength | FNonNeg)) {
1147 RefPtrWillBeRawPtr<CSSValue> val = createPrimitiveNumericValue(value);
1149 addProperty(propId, val.release(), important);
1156 case CSSPropertyWebkitPerspectiveOrigin:
1157 case CSSPropertyWebkitPerspectiveOriginX:
1158 case CSSPropertyWebkitPerspectiveOriginY: {
1159 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
1160 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
1161 CSSPropertyID propId1, propId2;
1162 if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
1163 addProperty(propId1, val1.release(), important);
1165 addProperty(propId2, val2.release(), important);
1170 case CSSPropertyAnimationDelay:
1171 case CSSPropertyAnimationDirection:
1172 case CSSPropertyAnimationDuration:
1173 case CSSPropertyAnimationFillMode:
1174 case CSSPropertyAnimationName:
1175 case CSSPropertyAnimationPlayState:
1176 case CSSPropertyAnimationIterationCount:
1177 case CSSPropertyAnimationTimingFunction:
1178 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
1180 case CSSPropertyWebkitAnimationDelay:
1181 case CSSPropertyWebkitAnimationDirection:
1182 case CSSPropertyWebkitAnimationDuration:
1183 case CSSPropertyWebkitAnimationFillMode:
1184 case CSSPropertyWebkitAnimationName:
1185 case CSSPropertyWebkitAnimationPlayState:
1186 case CSSPropertyWebkitAnimationIterationCount:
1187 case CSSPropertyWebkitAnimationTimingFunction:
1188 case CSSPropertyTransitionDelay:
1189 case CSSPropertyTransitionDuration:
1190 case CSSPropertyTransitionTimingFunction:
1191 case CSSPropertyTransitionProperty:
1192 case CSSPropertyWebkitTransitionDelay:
1193 case CSSPropertyWebkitTransitionDuration:
1194 case CSSPropertyWebkitTransitionTimingFunction:
1195 case CSSPropertyWebkitTransitionProperty: {
1196 RefPtrWillBeRawPtr<CSSValue> val = nullptr;
1197 AnimationParseContext context;
1198 if (parseAnimationProperty(propId, val, context)) {
1199 addPropertyWithPrefixingVariant(propId, val.release(), important);
1205 case CSSPropertyJustifySelf:
1206 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1209 return parseItemPositionOverflowPosition(propId, important);
1210 case CSSPropertyGridAutoColumns:
1211 case CSSPropertyGridAutoRows:
1212 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1214 parsedValue = parseGridTrackSize(*m_valueList);
1217 case CSSPropertyGridTemplateColumns:
1218 case CSSPropertyGridTemplateRows:
1219 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1221 return parseGridTrackList(propId, important);
1223 case CSSPropertyGridColumnEnd:
1224 case CSSPropertyGridColumnStart:
1225 case CSSPropertyGridRowEnd:
1226 case CSSPropertyGridRowStart:
1227 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1229 parsedValue = parseGridPosition();
1232 case CSSPropertyGridColumn:
1233 case CSSPropertyGridRow:
1234 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1236 return parseGridItemPositionShorthand(propId, important);
1238 case CSSPropertyGridArea:
1239 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1241 return parseGridAreaShorthand(important);
1243 case CSSPropertyGridTemplateAreas:
1244 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
1246 parsedValue = parseGridTemplateAreas();
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 case CSSPropertyShapePadding:
1487 validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FLength | FNonNeg));
1489 case CSSPropertyShapeImageThreshold:
1490 validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FNumber));
1493 case CSSPropertyTouchAction:
1494 // auto | none | [pan-x || pan-y] | manipulation
1495 return parseTouchAction(important);
1497 case CSSPropertyAlignSelf:
1498 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1499 return parseItemPositionOverflowPosition(propId, important);
1501 case CSSPropertyAlignItems:
1502 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1503 return parseItemPositionOverflowPosition(propId, important);
1505 case CSSPropertyBorderBottomStyle:
1506 case CSSPropertyBorderCollapse:
1507 case CSSPropertyBorderLeftStyle:
1508 case CSSPropertyBorderRightStyle:
1509 case CSSPropertyBorderTopStyle:
1510 case CSSPropertyBoxSizing:
1511 case CSSPropertyCaptionSide:
1512 case CSSPropertyClear:
1513 case CSSPropertyDirection:
1514 case CSSPropertyDisplay:
1515 case CSSPropertyEmptyCells:
1516 case CSSPropertyFloat:
1517 case CSSPropertyFontStyle:
1518 case CSSPropertyImageRendering:
1519 case CSSPropertyListStylePosition:
1520 case CSSPropertyListStyleType:
1521 case CSSPropertyObjectFit:
1522 case CSSPropertyOutlineStyle:
1523 case CSSPropertyOverflowWrap:
1524 case CSSPropertyOverflowX:
1525 case CSSPropertyOverflowY:
1526 case CSSPropertyPageBreakAfter:
1527 case CSSPropertyPageBreakBefore:
1528 case CSSPropertyPageBreakInside:
1529 case CSSPropertyPointerEvents:
1530 case CSSPropertyPosition:
1531 case CSSPropertyResize:
1532 case CSSPropertySpeak:
1533 case CSSPropertyTableLayout:
1534 case CSSPropertyTextAlignLast:
1535 case CSSPropertyTextJustify:
1536 case CSSPropertyTextLineThroughMode:
1537 case CSSPropertyTextLineThroughStyle:
1538 case CSSPropertyTextOverflow:
1539 case CSSPropertyTextOverlineMode:
1540 case CSSPropertyTextOverlineStyle:
1541 case CSSPropertyTextRendering:
1542 case CSSPropertyTextTransform:
1543 case CSSPropertyTextUnderlineMode:
1544 case CSSPropertyTextUnderlineStyle:
1545 case CSSPropertyTouchActionDelay:
1546 case CSSPropertyVisibility:
1547 case CSSPropertyWebkitAppearance:
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;
1611 // FIXME: crbug.com/154772 Unimplemented css-transforms properties
1612 case CSSPropertyBackfaceVisibility:
1613 case CSSPropertyPerspective:
1614 case CSSPropertyPerspectiveOrigin:
1615 case CSSPropertyTransform:
1616 case CSSPropertyTransformOrigin:
1619 return parseSVGValue(propId, important);
1622 if (validPrimitive) {
1623 parsedValue = parseValidPrimitive(id, value);
1624 m_valueList->next();
1626 ASSERT(!m_parsedCalculation);
1628 if (!m_valueList->current() || inShorthand()) {
1629 addProperty(propId, parsedValue.release(), important);
1636 void CSSPropertyParser::addFillValue(RefPtrWillBeRawPtr<CSSValue>& lval, PassRefPtrWillBeRawPtr<CSSValue> rval)
1639 if (lval->isBaseValueList())
1640 toCSSValueList(lval.get())->append(rval);
1642 PassRefPtrWillBeRawPtr<CSSValue> oldlVal(lval.release());
1643 PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
1644 list->append(oldlVal);
1653 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtrWillBeRawPtr<CSSValue>& cssValue)
1655 if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
1656 || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
1657 cssValue = cssValuePool().createIdentifierValue(parserValue->id);
1663 const int cMaxFillProperties = 9;
1665 bool CSSPropertyParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
1667 ASSERT(numProperties <= cMaxFillProperties);
1668 if (numProperties > cMaxFillProperties)
1671 ShorthandScope scope(this, propId);
1673 bool parsedProperty[cMaxFillProperties] = { false };
1674 RefPtrWillBeRawPtr<CSSValue> values[cMaxFillProperties];
1676 // Zero initialize the array of raw pointers.
1677 memset(&values, 0, sizeof(values));
1679 RefPtrWillBeRawPtr<CSSValue> clipValue = nullptr;
1680 RefPtrWillBeRawPtr<CSSValue> positionYValue = nullptr;
1681 RefPtrWillBeRawPtr<CSSValue> repeatYValue = nullptr;
1682 bool foundClip = false;
1684 bool foundPositionCSSProperty = false;
1686 while (m_valueList->current()) {
1687 CSSParserValue* val = m_valueList->current();
1688 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
1689 // We hit the end. Fill in all remaining values with the initial value.
1690 m_valueList->next();
1691 for (i = 0; i < numProperties; ++i) {
1692 if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
1693 // Color is not allowed except as the last item in a list for backgrounds.
1694 // Reject the entire property.
1697 if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
1698 addFillValue(values[i], cssValuePool().createImplicitInitialValue());
1699 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1700 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
1701 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1702 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
1703 if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
1704 // If background-origin wasn't present, then reset background-clip also.
1705 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
1708 parsedProperty[i] = false;
1710 if (!m_valueList->current())
1714 bool sizeCSSPropertyExpected = false;
1715 if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
1716 sizeCSSPropertyExpected = true;
1717 m_valueList->next();
1720 foundPositionCSSProperty = false;
1722 for (i = 0; !found && i < numProperties; ++i) {
1724 if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgroundSize && properties[i] != CSSPropertyWebkitMaskSize))
1726 if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgroundSize || properties[i] == CSSPropertyWebkitMaskSize))
1729 if (!parsedProperty[i]) {
1730 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
1731 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
1732 CSSPropertyID propId1, propId2;
1733 CSSParserValue* parserValue = m_valueList->current();
1734 // parseFillProperty() may modify m_implicitShorthand, so we MUST reset it
1735 // before EACH return below.
1736 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
1737 parsedProperty[i] = found = true;
1738 addFillValue(values[i], val1.release());
1739 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1740 addFillValue(positionYValue, val2.release());
1741 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1742 addFillValue(repeatYValue, val2.release());
1743 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
1744 // Reparse the value as a clip, and see if we succeed.
1745 if (parseBackgroundClip(parserValue, val1))
1746 addFillValue(clipValue, val1.release()); // The property parsed successfully.
1748 addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
1750 if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
1752 addFillValue(clipValue, val1.release());
1755 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1756 foundPositionCSSProperty = true;
1761 // if we didn't find at least one match, this is an
1762 // invalid shorthand and we have to ignore it
1764 m_implicitShorthand = false;
1769 // Now add all of the properties we found.
1770 for (i = 0; i < numProperties; i++) {
1771 // Fill in any remaining properties with the initial value.
1772 if (!parsedProperty[i]) {
1773 addFillValue(values[i], cssValuePool().createImplicitInitialValue());
1774 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1775 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
1776 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1777 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
1778 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
1779 // If background-origin wasn't present, then reset background-clip also.
1780 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
1783 if (properties[i] == CSSPropertyBackgroundPosition) {
1784 addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
1785 // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
1786 addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
1787 } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
1788 addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
1789 // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
1790 addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
1791 } else if (properties[i] == CSSPropertyBackgroundRepeat) {
1792 addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
1793 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
1794 addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
1795 } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
1796 addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
1797 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
1798 addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
1799 } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
1800 // Value is already set while updating origin
1802 else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i] && m_context.useLegacyBackgroundSizeShorthandBehavior())
1805 addProperty(properties[i], values[i].release(), important);
1807 // Add in clip values when we hit the corresponding origin property.
1808 if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
1809 addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
1810 else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
1811 addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
1814 m_implicitShorthand = false;
1818 void CSSPropertyParser::addAnimationValue(RefPtrWillBeRawPtr<CSSValue>& lval, PassRefPtrWillBeRawPtr<CSSValue> rval)
1821 if (lval->isValueList())
1822 toCSSValueList(lval.get())->append(rval);
1824 PassRefPtrWillBeRawPtr<CSSValue> oldVal(lval.release());
1825 PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
1826 list->append(oldVal);
1835 bool CSSPropertyParser::parseAnimationShorthand(CSSPropertyID propId, bool important)
1837 const StylePropertyShorthand& animationProperties = parsingShorthandForProperty(propId);
1838 const unsigned numProperties = 8;
1840 // The list of properties in the shorthand should be the same
1841 // length as the list with animation name in last position, even though they are
1842 // in a different order.
1843 ASSERT(numProperties == animationProperties.length());
1844 ASSERT(numProperties == shorthandForProperty(propId).length());
1846 ShorthandScope scope(this, propId);
1848 bool parsedProperty[numProperties] = { false };
1849 AnimationParseContext context;
1850 RefPtrWillBeRawPtr<CSSValue> values[numProperties];
1852 // Zero initialize the array of raw pointers.
1853 memset(&values, 0, sizeof(values));
1857 while (m_valueList->current()) {
1858 CSSParserValue* val = m_valueList->current();
1859 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
1860 // We hit the end. Fill in all remaining values with the initial value.
1861 m_valueList->next();
1862 for (i = 0; i < numProperties; ++i) {
1863 if (!parsedProperty[i])
1864 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
1865 parsedProperty[i] = false;
1867 if (!m_valueList->current())
1869 context.commitFirstAnimation();
1873 for (i = 0; i < numProperties; ++i) {
1874 if (!parsedProperty[i]) {
1875 RefPtrWillBeRawPtr<CSSValue> val = nullptr;
1876 if (parseAnimationProperty(animationProperties.properties()[i], val, context)) {
1877 parsedProperty[i] = found = true;
1878 addAnimationValue(values[i], val.release());
1884 // if we didn't find at least one match, this is an
1885 // invalid shorthand and we have to ignore it
1890 for (i = 0; i < numProperties; ++i) {
1891 // If we didn't find the property, set an intial value.
1892 if (!parsedProperty[i])
1893 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
1895 if (RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
1896 addPropertyWithPrefixingVariant(animationProperties.properties()[i], values[i].release(), important);
1898 addProperty(animationProperties.properties()[i], values[i].release(), important);
1904 bool CSSPropertyParser::parseTransitionShorthand(CSSPropertyID propId, bool important)
1906 const unsigned numProperties = 4;
1907 const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
1908 ASSERT(numProperties == shorthand.length());
1910 ShorthandScope scope(this, propId);
1912 bool parsedProperty[numProperties] = { false };
1913 AnimationParseContext context;
1914 RefPtrWillBeRawPtr<CSSValue> values[numProperties];
1916 // Zero initialize the array of raw pointers.
1917 memset(&values, 0, sizeof(values));
1921 while (m_valueList->current()) {
1922 CSSParserValue* val = m_valueList->current();
1923 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
1924 // We hit the end. Fill in all remaining values with the initial value.
1925 m_valueList->next();
1926 for (i = 0; i < numProperties; ++i) {
1927 if (!parsedProperty[i])
1928 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
1929 parsedProperty[i] = false;
1931 if (!m_valueList->current())
1933 context.commitFirstAnimation();
1937 for (i = 0; !found && i < numProperties; ++i) {
1938 if (!parsedProperty[i]) {
1939 RefPtrWillBeRawPtr<CSSValue> val = nullptr;
1940 if (parseAnimationProperty(shorthand.properties()[i], val, context)) {
1941 parsedProperty[i] = found = true;
1942 addAnimationValue(values[i], val.release());
1945 // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid.
1946 if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation())
1951 // if we didn't find at least one match, this is an
1952 // invalid shorthand and we have to ignore it
1957 // Fill in any remaining properties with the initial value.
1958 for (i = 0; i < numProperties; ++i) {
1959 if (!parsedProperty[i])
1960 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
1963 // Now add all of the properties we found.
1964 for (i = 0; i < numProperties; i++)
1965 addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].release(), important);
1970 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnWidth()
1972 CSSParserValue* value = m_valueList->current();
1973 // Always parse lengths in strict mode here, since it would be ambiguous otherwise when used in
1974 // the 'columns' shorthand property.
1975 if (value->id == CSSValueAuto
1976 || (validUnit(value, FLength | FNonNeg, HTMLStandardMode) && value->fValue)) {
1977 RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
1978 m_valueList->next();
1984 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnCount()
1986 CSSParserValue* value = m_valueList->current();
1987 if (value->id == CSSValueAuto
1988 || (!value->id && validUnit(value, FPositiveInteger, HTMLQuirksMode))) {
1989 RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
1990 m_valueList->next();
1996 bool CSSPropertyParser::parseColumnsShorthand(bool important)
1998 RefPtrWillBeRawPtr<CSSValue> columnWidth = nullptr;
1999 RefPtrWillBeRawPtr<CSSValue> columnCount = nullptr;
2000 bool hasPendingExplicitAuto = false;
2002 for (unsigned propertiesParsed = 0; CSSParserValue* value = m_valueList->current(); propertiesParsed++) {
2003 if (propertiesParsed >= 2)
2004 return false; // Too many values for this shorthand. Invalid declaration.
2005 if (!propertiesParsed && value->id == CSSValueAuto) {
2006 // 'auto' is a valid value for any of the two longhands, and at this point we
2007 // don't know which one(s) it is meant for. We need to see if there are other
2009 m_valueList->next();
2010 hasPendingExplicitAuto = true;
2013 if ((columnWidth = parseColumnWidth()))
2017 if ((columnCount = parseColumnCount()))
2020 // If we didn't find at least one match, this is an
2021 // invalid shorthand and we have to ignore it.
2025 if (hasPendingExplicitAuto) {
2026 // Time to assign the previously skipped 'auto' value to a property. If both properties are
2027 // unassigned at this point (i.e. 'columns:auto'), it doesn't matter that much which one we
2028 // set (although it does make a slight difference to web-inspector). The one we don't set
2029 // here will get an implicit 'auto' value further down.
2031 columnWidth = cssValuePool().createIdentifierValue(CSSValueAuto);
2033 ASSERT(!columnCount);
2034 columnCount = cssValuePool().createIdentifierValue(CSSValueAuto);
2037 ASSERT(columnCount || columnWidth);
2039 // Any unassigned property at this point will become implicit 'auto'.
2041 addProperty(CSSPropertyWebkitColumnWidth, columnWidth, important);
2043 addProperty(CSSPropertyWebkitColumnWidth, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
2045 addProperty(CSSPropertyWebkitColumnCount, columnCount, important);
2047 addProperty(CSSPropertyWebkitColumnCount, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
2051 bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
2053 // We try to match as many properties as possible
2054 // We set up an array of booleans to mark which property has been found,
2055 // and we try to search for properties until it makes no longer any sense.
2056 ShorthandScope scope(this, propId);
2059 unsigned propertiesParsed = 0;
2060 bool propertyFound[6] = { false, false, false, false, false, false }; // 6 is enough size.
2062 while (m_valueList->current()) {
2064 for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
2065 if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
2066 propertyFound[propIndex] = found = true;
2071 // if we didn't find at least one match, this is an
2072 // invalid shorthand and we have to ignore it
2077 if (propertiesParsed == shorthand.length())
2080 // Fill in any remaining properties with the initial value.
2081 ImplicitScope implicitScope(this, PropertyImplicit);
2082 const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization();
2083 for (unsigned i = 0; i < shorthand.length(); ++i) {
2084 if (propertyFound[i])
2087 if (propertiesForInitialization) {
2088 const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]);
2089 for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
2090 addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
2092 addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
2098 bool CSSPropertyParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties, bool important)
2100 /* From the CSS 2 specs, 8.3
2101 * If there is only one value, it applies to all sides. If there are two values, the top and
2102 * bottom margins are set to the first value and the right and left margins are set to the second.
2103 * If there are three values, the top is set to the first value, the left and right are set to the
2104 * second, and the bottom is set to the third. If there are four values, they apply to the top,
2105 * right, bottom, and left, respectively.
2108 int num = inShorthand() ? 1 : m_valueList->size();
2110 ShorthandScope scope(this, propId);
2112 // the order is top, right, bottom, left
2115 if (!parseValue(properties[0], important))
2117 CSSValue* value = m_parsedProperties.last().value();
2118 ImplicitScope implicitScope(this, PropertyImplicit);
2119 addProperty(properties[1], value, important);
2120 addProperty(properties[2], value, important);
2121 addProperty(properties[3], value, important);
2125 if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
2127 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
2128 ImplicitScope implicitScope(this, PropertyImplicit);
2129 addProperty(properties[2], value, important);
2130 value = m_parsedProperties[m_parsedProperties.size() - 2].value();
2131 addProperty(properties[3], value, important);
2135 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
2137 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
2138 ImplicitScope implicitScope(this, PropertyImplicit);
2139 addProperty(properties[3], value, important);
2143 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
2144 !parseValue(properties[2], important) || !parseValue(properties[3], important))
2156 // auto | <identifier>
2157 bool CSSPropertyParser::parsePage(CSSPropertyID propId, bool important)
2159 ASSERT(propId == CSSPropertyPage);
2161 if (m_valueList->size() != 1)
2164 CSSParserValue* value = m_valueList->current();
2168 if (value->id == CSSValueAuto) {
2169 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
2171 } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
2172 addProperty(propId, createPrimitiveStringValue(value), important);
2178 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
2179 bool CSSPropertyParser::parseSize(CSSPropertyID propId, bool important)
2181 ASSERT(propId == CSSPropertySize);
2183 if (m_valueList->size() > 2)
2186 CSSParserValue* value = m_valueList->current();
2190 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
2193 SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
2194 if (paramType == None)
2197 // Second parameter, if any.
2198 value = m_valueList->next();
2200 paramType = parseSizeParameter(parsedValues.get(), value, paramType);
2201 if (paramType == None)
2205 addProperty(propId, parsedValues.release(), important);
2209 CSSPropertyParser::SizeParameterType CSSPropertyParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
2211 switch (value->id) {
2213 if (prevParamType == None) {
2214 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
2218 case CSSValueLandscape:
2219 case CSSValuePortrait:
2220 if (prevParamType == None || prevParamType == PageSize) {
2221 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
2230 case CSSValueLedger:
2232 case CSSValueLetter:
2233 if (prevParamType == None || prevParamType == Orientation) {
2234 // Normalize to Page Size then Orientation order by prepending.
2235 // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
2236 parsedValues->prepend(cssValuePool().createIdentifierValue(value->id));
2241 if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) {
2242 parsedValues->append(createPrimitiveNumericValue(value));
2251 // [ <string> <string> ]+ | inherit | none
2252 // inherit and none are handled in parseValue.
2253 bool CSSPropertyParser::parseQuotes(CSSPropertyID propId, bool important)
2255 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
2256 while (CSSParserValue* val = m_valueList->current()) {
2257 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
2258 if (val->unit == CSSPrimitiveValue::CSS_STRING)
2259 parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
2262 values->append(parsedValue.release());
2263 m_valueList->next();
2265 if (values->length()) {
2266 addProperty(propId, values.release(), important);
2267 m_valueList->next();
2273 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
2274 // in CSS 2.1 this got somewhat reduced:
2275 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
2276 bool CSSPropertyParser::parseContent(CSSPropertyID propId, bool important)
2278 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
2280 while (CSSParserValue* val = m_valueList->current()) {
2281 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
2282 if (val->unit == CSSPrimitiveValue::CSS_URI) {
2284 parsedValue = CSSImageValue::create(val->string, completeURL(val->string));
2285 } else if (val->unit == CSSParserValue::Function) {
2286 // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
2287 CSSParserValueList* args = val->function->args.get();
2290 if (equalIgnoringCase(val->function->name, "attr(")) {
2291 parsedValue = parseAttr(args);
2294 } else if (equalIgnoringCase(val->function->name, "counter(")) {
2295 parsedValue = parseCounterContent(args, false);
2298 } else if (equalIgnoringCase(val->function->name, "counters(")) {
2299 parsedValue = parseCounterContent(args, true);
2302 } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
2303 parsedValue = parseImageSet(m_valueList.get());
2306 } else if (isGeneratedImageValue(val)) {
2307 if (!parseGeneratedImage(m_valueList.get(), parsedValue))
2311 } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
2317 // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
2321 case CSSValueOpenQuote:
2322 case CSSValueCloseQuote:
2323 case CSSValueNoOpenQuote:
2324 case CSSValueNoCloseQuote:
2326 case CSSValueNormal:
2327 parsedValue = cssValuePool().createIdentifierValue(val->id);
2331 } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
2332 parsedValue = createPrimitiveStringValue(val);
2336 values->append(parsedValue.release());
2337 m_valueList->next();
2340 if (values->length()) {
2341 addProperty(propId, values.release(), important);
2342 m_valueList->next();
2349 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAttr(CSSParserValueList* args)
2351 if (args->size() != 1)
2354 CSSParserValue* a = args->current();
2356 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
2359 String attrName = a->string;
2360 // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
2361 // But HTML attribute names can't have those characters, and we should not
2362 // even parse them inside attr().
2363 if (attrName[0] == '-')
2366 if (m_context.isHTMLDocument())
2367 attrName = attrName.lower();
2369 return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
2372 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBackgroundColor()
2374 CSSValueID id = m_valueList->current()->id;
2375 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
2376 (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
2377 return cssValuePool().createIdentifierValue(id);
2378 return parseColor();
2381 bool CSSPropertyParser::parseFillImage(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value)
2383 if (valueList->current()->id == CSSValueNone) {
2384 value = cssValuePool().createIdentifierValue(CSSValueNone);
2387 if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
2388 value = CSSImageValue::create(valueList->current()->string, completeURL(valueList->current()->string));
2392 if (isGeneratedImageValue(valueList->current()))
2393 return parseGeneratedImage(valueList, value);
2395 if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) {
2396 value = parseImageSet(m_valueList.get());
2404 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionX(CSSParserValueList* valueList)
2406 int id = valueList->current()->id;
2407 if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
2409 if (id == CSSValueRight)
2411 else if (id == CSSValueCenter)
2413 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2415 if (validUnit(valueList->current(), FPercent | FLength))
2416 return createPrimitiveNumericValue(valueList->current());
2420 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionY(CSSParserValueList* valueList)
2422 int id = valueList->current()->id;
2423 if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
2425 if (id == CSSValueBottom)
2427 else if (id == CSSValueCenter)
2429 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2431 if (validUnit(valueList->current(), FPercent | FLength))
2432 return createPrimitiveNumericValue(valueList->current());
2436 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode)
2438 CSSValueID id = valueList->current()->id;
2439 if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
2441 if (id == CSSValueLeft || id == CSSValueRight) {
2442 if (cumulativeFlags & XFillPosition)
2444 cumulativeFlags |= XFillPosition;
2445 individualFlag = XFillPosition;
2446 if (id == CSSValueRight)
2449 else if (id == CSSValueTop || id == CSSValueBottom) {
2450 if (cumulativeFlags & YFillPosition)
2452 cumulativeFlags |= YFillPosition;
2453 individualFlag = YFillPosition;
2454 if (id == CSSValueBottom)
2456 } else if (id == CSSValueCenter) {
2457 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
2459 cumulativeFlags |= AmbiguousFillPosition;
2460 individualFlag = AmbiguousFillPosition;
2463 if (parsingMode == ResolveValuesAsKeyword)
2464 return cssValuePool().createIdentifierValue(id);
2466 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2468 if (validUnit(valueList->current(), FPercent | FLength)) {
2469 if (!cumulativeFlags) {
2470 cumulativeFlags |= XFillPosition;
2471 individualFlag = XFillPosition;
2472 } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
2473 cumulativeFlags |= YFillPosition;
2474 individualFlag = YFillPosition;
2476 if (m_parsedCalculation)
2477 m_parsedCalculation.release();
2480 return createPrimitiveNumericValue(valueList->current());
2485 static bool isValueConflictingWithCurrentEdge(int value1, int value2)
2487 if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSValueLeft || value2 == CSSValueRight))
2490 if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSValueTop || value2 == CSSValueBottom))
2496 static bool isFillPositionKeyword(CSSValueID value)
2498 return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter;
2501 void CSSPropertyParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2)
2503 // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <percentage> | <length> ]
2504 // In the case of 4 values <position> requires the second value to be a length or a percentage.
2505 if (isFillPositionKeyword(parsedValue2->getValueID()))
2508 unsigned cumulativeFlags = 0;
2509 FillPositionFlag value3Flag = InvalidFillPosition;
2510 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
2514 CSSValueID ident1 = parsedValue1->getValueID();
2515 CSSValueID ident3 = value3->getValueID();
2517 if (ident1 == CSSValueCenter)
2520 if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
2523 // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
2524 // needed as the second call to parseFillPositionComponent was on purpose not checking it. In the
2525 // case of two values top 20px is invalid but in the case of 4 values it becomes valid.
2526 if (isValueConflictingWithCurrentEdge(ident1, ident3))
2531 cumulativeFlags = 0;
2532 FillPositionFlag value4Flag = InvalidFillPosition;
2533 RefPtrWillBeRawPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(valueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
2537 // 4th value must be a length or a percentage.
2538 if (isFillPositionKeyword(value4->getValueID()))
2541 value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
2542 value2 = createPrimitiveValuePair(value3, value4);
2544 if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
2545 value1.swap(value2);
2549 void CSSPropertyParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2)
2551 unsigned cumulativeFlags = 0;
2552 FillPositionFlag value3Flag = InvalidFillPosition;
2553 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
2555 // value3 is not an expected value, we return.
2561 bool swapNeeded = false;
2562 CSSValueID ident1 = parsedValue1->getValueID();
2563 CSSValueID ident2 = parsedValue2->getValueID();
2564 CSSValueID ident3 = value3->getValueID();
2566 CSSValueID firstPositionKeyword;
2567 CSSValueID secondPositionKeyword;
2569 if (ident1 == CSSValueCenter) {
2570 // <position> requires the first 'center' to be followed by a keyword.
2571 if (!isFillPositionKeyword(ident2))
2574 // If 'center' is the first keyword then the last one needs to be a length.
2575 if (isFillPositionKeyword(ident3))
2578 firstPositionKeyword = CSSValueLeft;
2579 if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
2580 firstPositionKeyword = CSSValueTop;
2583 value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
2584 value2 = createPrimitiveValuePair(parsedValue2, value3);
2585 } else if (ident3 == CSSValueCenter) {
2586 if (isFillPositionKeyword(ident2))
2589 secondPositionKeyword = CSSValueTop;
2590 if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
2591 secondPositionKeyword = CSSValueLeft;
2594 value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
2595 value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
2597 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstPositionValue = nullptr;
2598 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondPositionValue = nullptr;
2600 if (isFillPositionKeyword(ident2)) {
2601 // To match CSS grammar, we should only accept: [ center | left | right | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ].
2602 ASSERT(ident2 != CSSValueCenter);
2604 if (isFillPositionKeyword(ident3))
2607 secondPositionValue = value3;
2608 secondPositionKeyword = ident2;
2609 firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
2611 // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
2612 if (!isFillPositionKeyword(ident3))
2615 firstPositionValue = parsedValue2;
2616 secondPositionKeyword = ident3;
2617 secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
2620 if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
2623 value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue);
2624 value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue);
2627 if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
2628 value1.swap(value2);
2631 CSSPrimitiveValue* first = toCSSPrimitiveValue(value1.get());
2632 CSSPrimitiveValue* second = toCSSPrimitiveValue(value2.get());
2633 ident1 = first->getPairValue()->first()->getValueID();
2634 ident2 = second->getPairValue()->first()->getValueID();
2635 ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
2636 ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
2640 inline bool CSSPropertyParser::isPotentialPositionValue(CSSParserValue* value)
2642 return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue);
2645 void CSSPropertyParser::parseFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
2647 unsigned numberOfValues = 0;
2648 for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++numberOfValues) {
2649 CSSParserValue* current = valueList->valueAt(i);
2650 if (isComma(current) || !current || isForwardSlashOperator(current) || !isPotentialPositionValue(current))
2654 if (numberOfValues > 4)
2657 // If we are parsing two values, we can safely call the CSS 2.1 parsing function and return.
2658 if (numberOfValues <= 2) {
2659 parse2ValuesFillPosition(valueList, value1, value2);
2663 ASSERT(numberOfValues > 2 && numberOfValues <= 4);
2665 CSSParserValue* value = valueList->current();
2667 // <position> requires the first value to be a background keyword.
2668 if (!isFillPositionKeyword(value->id))
2671 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
2672 unsigned cumulativeFlags = 0;
2673 FillPositionFlag value1Flag = InvalidFillPosition;
2674 FillPositionFlag value2Flag = InvalidFillPosition;
2675 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
2681 // In case we are parsing more than two values, relax the check inside of parseFillPositionComponent. top 20px is
2682 // a valid start for <position>.
2683 cumulativeFlags = AmbiguousFillPosition;
2684 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
2692 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(value1.get());
2693 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(value2.get());
2698 // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
2699 if (parsedValue2->getValueID() == CSSValueCenter)
2702 if (numberOfValues == 3)
2703 parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
2705 parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
2708 void CSSPropertyParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
2710 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
2711 unsigned cumulativeFlags = 0;
2712 FillPositionFlag value1Flag = InvalidFillPosition;
2713 FillPositionFlag value2Flag = InvalidFillPosition;
2714 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
2718 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
2719 // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the
2720 // value was explicitly specified for our property.
2721 CSSParserValue* value = valueList->next();
2723 // First check for the comma. If so, we are finished parsing this value or value pair.
2728 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
2732 if (!inShorthand()) {
2740 // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
2741 // is simply 50%. This is our default.
2742 // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
2743 // For left/right/center, the default of 50% in the y is still correct.
2744 value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
2746 if (value1Flag == YFillPosition || value2Flag == XFillPosition)
2747 value1.swap(value2);
2750 void CSSPropertyParser::parseFillRepeat(RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
2752 CSSValueID id = m_valueList->current()->id;
2753 if (id == CSSValueRepeatX) {
2754 m_implicitShorthand = true;
2755 value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
2756 value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
2757 m_valueList->next();
2760 if (id == CSSValueRepeatY) {
2761 m_implicitShorthand = true;
2762 value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
2763 value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
2764 m_valueList->next();
2767 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
2768 value1 = cssValuePool().createIdentifierValue(id);
2774 CSSParserValue* value = m_valueList->next();
2776 // Parse the second value if one is available
2777 if (value && !isComma(value)) {
2779 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
2780 value2 = cssValuePool().createIdentifierValue(id);
2781 m_valueList->next();
2786 // If only one value was specified, value2 is the same as value1.
2787 m_implicitShorthand = true;
2788 value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get())->getValueID());
2791 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
2794 CSSParserValue* value = m_valueList->current();
2796 if (value->id == CSSValueContain || value->id == CSSValueCover)
2797 return cssValuePool().createIdentifierValue(value->id);
2799 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = nullptr;
2801 if (value->id == CSSValueAuto)
2802 parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
2804 if (!validUnit(value, FLength | FPercent))
2806 parsedValue1 = createPrimitiveNumericValue(value);
2809 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr;
2810 if ((value = m_valueList->next())) {
2811 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
2813 else if (value->id != CSSValueAuto) {
2814 if (!validUnit(value, FLength | FPercent)) {
2817 // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
2818 m_valueList->previous();
2820 parsedValue2 = createPrimitiveNumericValue(value);
2822 } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
2823 // For backwards compatibility we set the second value to the first if it is omitted.
2824 // We only need to do this for -webkit-background-size. It should be safe to let masks match
2825 // the real property.
2826 parsedValue2 = parsedValue1;
2830 return parsedValue1;
2831 return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release());
2834 bool CSSPropertyParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
2835 RefPtrWillBeRawPtr<CSSValue>& retValue1, RefPtrWillBeRawPtr<CSSValue>& retValue2)
2837 RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
2838 RefPtrWillBeRawPtr<CSSValueList> values2 = nullptr;
2839 CSSParserValue* val;
2840 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
2841 RefPtrWillBeRawPtr<CSSValue> value2 = nullptr;
2843 bool allowComma = false;
2845 retValue1 = retValue2 = nullptr;
2848 if (propId == CSSPropertyBackgroundPosition) {
2849 propId1 = CSSPropertyBackgroundPositionX;
2850 propId2 = CSSPropertyBackgroundPositionY;
2851 } else if (propId == CSSPropertyWebkitMaskPosition) {
2852 propId1 = CSSPropertyWebkitMaskPositionX;
2853 propId2 = CSSPropertyWebkitMaskPositionY;
2854 } else if (propId == CSSPropertyBackgroundRepeat) {
2855 propId1 = CSSPropertyBackgroundRepeatX;
2856 propId2 = CSSPropertyBackgroundRepeatY;
2857 } else if (propId == CSSPropertyWebkitMaskRepeat) {
2858 propId1 = CSSPropertyWebkitMaskRepeatX;
2859 propId2 = CSSPropertyWebkitMaskRepeatY;
2862 while ((val = m_valueList->current())) {
2863 RefPtrWillBeRawPtr<CSSValue> currValue = nullptr;
2864 RefPtrWillBeRawPtr<CSSValue> currValue2 = nullptr;
2869 m_valueList->next();
2874 case CSSPropertyBackgroundColor:
2875 currValue = parseBackgroundColor();
2877 m_valueList->next();
2879 case CSSPropertyBackgroundAttachment:
2880 if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
2881 currValue = cssValuePool().createIdentifierValue(val->id);
2882 m_valueList->next();
2885 case CSSPropertyBackgroundImage:
2886 case CSSPropertyWebkitMaskImage:
2887 if (parseFillImage(m_valueList.get(), currValue))
2888 m_valueList->next();
2890 case CSSPropertyWebkitBackgroundClip:
2891 case CSSPropertyWebkitBackgroundOrigin:
2892 case CSSPropertyWebkitMaskClip:
2893 case CSSPropertyWebkitMaskOrigin:
2894 // The first three values here are deprecated and do not apply to the version of the property that has
2895 // the -webkit- prefix removed.
2896 if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
2897 val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
2898 ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
2899 (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
2900 currValue = cssValuePool().createIdentifierValue(val->id);
2901 m_valueList->next();
2904 case CSSPropertyBackgroundClip:
2905 if (parseBackgroundClip(val, currValue))
2906 m_valueList->next();
2908 case CSSPropertyBackgroundOrigin:
2909 if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
2910 currValue = cssValuePool().createIdentifierValue(val->id);
2911 m_valueList->next();
2914 case CSSPropertyBackgroundPosition:
2915 case CSSPropertyWebkitMaskPosition:
2916 parseFillPosition(m_valueList.get(), currValue, currValue2);
2917 // parseFillPosition advances the m_valueList pointer.
2919 case CSSPropertyBackgroundPositionX:
2920 case CSSPropertyWebkitMaskPositionX: {
2921 currValue = parseFillPositionX(m_valueList.get());
2923 m_valueList->next();
2926 case CSSPropertyBackgroundPositionY:
2927 case CSSPropertyWebkitMaskPositionY: {
2928 currValue = parseFillPositionY(m_valueList.get());
2930 m_valueList->next();
2933 case CSSPropertyWebkitBackgroundComposite:
2934 case CSSPropertyWebkitMaskComposite:
2935 if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) {
2936 currValue = cssValuePool().createIdentifierValue(val->id);
2937 m_valueList->next();
2940 case CSSPropertyBackgroundBlendMode:
2941 if (val->id == CSSValueNormal || val->id == CSSValueMultiply
2942 || val->id == CSSValueScreen || val->id == CSSValueOverlay || val->id == CSSValueDarken
2943 || val->id == CSSValueLighten || val->id == CSSValueColorDodge || val->id == CSSValueColorBurn
2944 || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference
2945 || val->id == CSSValueExclusion || val->id == CSSValueHue || val->id == CSSValueSaturation
2946 || val->id == CSSValueColor || val->id == CSSValueLuminosity) {
2947 currValue = cssValuePool().createIdentifierValue(val->id);
2948 m_valueList->next();
2951 case CSSPropertyBackgroundRepeat:
2952 case CSSPropertyWebkitMaskRepeat:
2953 parseFillRepeat(currValue, currValue2);
2954 // parseFillRepeat advances the m_valueList pointer
2956 case CSSPropertyBackgroundSize:
2957 case CSSPropertyWebkitBackgroundSize:
2958 case CSSPropertyWebkitMaskSize: {
2959 currValue = parseFillSize(propId, allowComma);
2961 m_valueList->next();
2964 case CSSPropertyMaskSourceType: {
2965 if (RuntimeEnabledFeatures::cssMaskSourceTypeEnabled()) {
2966 if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id == CSSValueLuminance) {
2967 currValue = cssValuePool().createIdentifierValue(val->id);
2968 m_valueList->next();
2970 currValue = nullptr;
2981 if (value && !values) {
2982 values = CSSValueList::createCommaSeparated();
2983 values->append(value.release());
2986 if (value2 && !values2) {
2987 values2 = CSSValueList::createCommaSeparated();
2988 values2->append(value2.release());
2992 values->append(currValue.release());
2994 value = currValue.release();
2997 values2->append(currValue2.release());
2999 value2 = currValue2.release();
3003 // When parsing any fill shorthand property, we let it handle building up the lists for all
3009 if (values && values->length()) {
3010 retValue1 = values.release();
3011 if (values2 && values2->length())
3012 retValue2 = values2.release();
3016 retValue1 = value.release();
3017 retValue2 = value2.release();
3023 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDelay()
3025 CSSParserValue* value = m_valueList->current();
3026 if (validUnit(value, FTime))
3027 return createPrimitiveNumericValue(value);
3031 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDirection()
3033 CSSParserValue* value = m_valueList->current();
3034 if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
3035 return cssValuePool().createIdentifierValue(value->id);
3039 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDuration()
3041 CSSParserValue* value = m_valueList->current();
3042 if (validUnit(value, FTime | FNonNeg))
3043 return createPrimitiveNumericValue(value);
3047 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationFillMode()
3049 CSSParserValue* value = m_valueList->current();
3050 if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
3051 return cssValuePool().createIdentifierValue(value->id);
3055 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationIterationCount()
3057 CSSParserValue* value = m_valueList->current();
3058 if (value->id == CSSValueInfinite)
3059 return cssValuePool().createIdentifierValue(value->id);
3060 if (validUnit(value, FNumber | FNonNeg))
3061 return createPrimitiveNumericValue(value);
3065 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationName()
3067 CSSParserValue* value = m_valueList->current();
3068 if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
3069 if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value, "none"))) {
3070 return cssValuePool().createIdentifierValue(CSSValueNone);
3072 return createPrimitiveStringValue(value);
3078 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationPlayState()
3080 CSSParserValue* value = m_valueList->current();
3081 if (value->id == CSSValueRunning || value->id == CSSValuePaused)
3082 return cssValuePool().createIdentifierValue(value->id);
3086 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationProperty(AnimationParseContext& context)
3088 CSSParserValue* value = m_valueList->current();
3089 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
3091 CSSPropertyID result = cssPropertyID(value->string);
3092 if (result && RuntimeCSSEnabled::isCSSPropertyEnabled(result))
3093 return cssValuePool().createIdentifierValue(result);
3094 if (equalIgnoringCase(value, "all")) {
3095 context.sawAnimationPropertyKeyword();
3096 return cssValuePool().createIdentifierValue(CSSValueAll);
3098 if (equalIgnoringCase(value, "none")) {
3099 context.commitAnimationPropertyKeyword();
3100 context.sawAnimationPropertyKeyword();
3101 return cssValuePool().createIdentifierValue(CSSValueNone);
3106 bool CSSPropertyParser::parseTransformOriginShorthand(RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, RefPtrWillBeRawPtr<CSSValue>& value3)
3108 parse2ValuesFillPosition(m_valueList.get(), value1, value2);
3111 if (m_valueList->current()) {
3112 if (validUnit(m_valueList->current(), FLength)) {
3113 value3 = createPrimitiveNumericValue(m_valueList->current());
3114 m_valueList->next();
3119 value3 = cssValuePool().createImplicitInitialValue();
3123 bool CSSPropertyParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
3125 CSSParserValue* v = args->current();
3126 if (!validUnit(v, FNumber))
3131 // The last number in the function has no comma after it, so we're done.
3139 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationTimingFunction()
3141 CSSParserValue* value = m_valueList->current();
3142 if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
3143 || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd
3144 || (value->id == CSSValueStepMiddle && RuntimeEnabledFeatures::webAnimationsAPIEnabled()))
3145 return cssValuePool().createIdentifierValue(value->id);
3147 // We must be a function.
3148 if (value->unit != CSSParserValue::Function)
3151 CSSParserValueList* args = value->function->args.get();
3153 if (equalIgnoringCase(value->function->name, "steps(")) {
3154 // For steps, 1 or 2 params must be specified (comma-separated)
3155 if (!args || (args->size() != 1 && args->size() != 3))
3158 // There are two values.
3160 StepsTimingFunction::StepAtPosition stepAtPosition = StepsTimingFunction::StepAtEnd;
3162 CSSParserValue* v = args->current();
3163 if (!validUnit(v, FInteger))
3165 numSteps = clampToInteger(v->fValue);
3171 // There is a comma so we need to parse the second value
3176 case CSSValueMiddle:
3177 if (!RuntimeEnabledFeatures::webAnimationsAPIEnabled())
3179 stepAtPosition = StepsTimingFunction::StepAtMiddle;
3182 stepAtPosition = StepsTimingFunction::StepAtStart;
3185 stepAtPosition = StepsTimingFunction::StepAtEnd;
3192 return CSSStepsTimingFunctionValue::create(numSteps, stepAtPosition);
3195 if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
3196 // For cubic bezier, 4 values must be specified.
3197 if (!args || args->size() != 7)
3200 // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range.
3201 double x1, y1, x2, y2;
3203 if (!parseCubicBezierTimingFunctionValue(args, x1))
3205 if (x1 < 0 || x1 > 1)
3207 if (!parseCubicBezierTimingFunctionValue(args, y1))
3209 if (!parseCubicBezierTimingFunctionValue(args, x2))
3211 if (x2 < 0 || x2 > 1)
3213 if (!parseCubicBezierTimingFunctionValue(args, y2))
3216 return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
3222 bool CSSPropertyParser::parseAnimationProperty(CSSPropertyID propId, RefPtrWillBeRawPtr<CSSValue>& result, AnimationParseContext& context)
3224 RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
3225 CSSParserValue* val;
3226 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
3227 bool allowComma = false;
3231 while ((val = m_valueList->current())) {
3232 RefPtrWillBeRawPtr<CSSValue> currValue = nullptr;
3236 m_valueList->next();
3241 case CSSPropertyAnimationDelay:
3242 case CSSPropertyWebkitAnimationDelay:
3243 case CSSPropertyTransitionDelay:
3244 case CSSPropertyWebkitTransitionDelay:
3245 currValue = parseAnimationDelay();
3247 m_valueList->next();
3249 case CSSPropertyAnimationDirection:
3250 case CSSPropertyWebkitAnimationDirection:
3251 currValue = parseAnimationDirection();
3253 m_valueList->next();
3255 case CSSPropertyAnimationDuration:
3256 case CSSPropertyWebkitAnimationDuration:
3257 case CSSPropertyTransitionDuration:
3258 case CSSPropertyWebkitTransitionDuration:
3259 currValue = parseAnimationDuration();
3261 m_valueList->next();
3263 case CSSPropertyAnimationFillMode:
3264 case CSSPropertyWebkitAnimationFillMode:
3265 currValue = parseAnimationFillMode();
3267 m_valueList->next();
3269 case CSSPropertyAnimationIterationCount:
3270 case CSSPropertyWebkitAnimationIterationCount:
3271 currValue = parseAnimationIterationCount();
3273 m_valueList->next();
3275 case CSSPropertyAnimationName:
3276 case CSSPropertyWebkitAnimationName:
3277 currValue = parseAnimationName();
3279 m_valueList->next();
3281 case CSSPropertyAnimationPlayState:
3282 case CSSPropertyWebkitAnimationPlayState:
3283 currValue = parseAnimationPlayState();
3285 m_valueList->next();
3287 case CSSPropertyTransitionProperty:
3288 case CSSPropertyWebkitTransitionProperty:
3289 currValue = parseAnimationProperty(context);
3290 if (value && !context.animationPropertyKeywordAllowed())
3293 m_valueList->next();
3295 case CSSPropertyAnimationTimingFunction:
3296 case CSSPropertyWebkitAnimationTimingFunction:
3297 case CSSPropertyTransitionTimingFunction:
3298 case CSSPropertyWebkitTransitionTimingFunction:
3299 currValue = parseAnimationTimingFunction();
3301 m_valueList->next();
3304 ASSERT_NOT_REACHED();
3311 if (value && !values) {
3312 values = CSSValueList::createCommaSeparated();
3313 values->append(value.release());
3317 values->append(currValue.release());
3319 value = currValue.release();
3324 // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
3330 if (values && values->length()) {
3331 result = values.release();
3335 result = value.release();
3341 // The function parses [ <integer> || <string> ] in <grid-line> (which can be stand alone or with 'span').
3342 bool CSSPropertyParser::parseIntegerOrStringFromGridPosition(RefPtrWillBeRawPtr<CSSPrimitiveValue>& numericValue, RefPtrWillBeRawPtr<CSSPrimitiveValue>& gridLineName)
3344 CSSParserValue* value = m_valueList->current();
3345 if (validUnit(value, FInteger) && value->fValue) {
3346 numericValue = createPrimitiveNumericValue(value);
3347 value = m_valueList->next();
3348 if (value && value->unit == CSSPrimitiveValue::CSS_STRING) {
3349 gridLineName = createPrimitiveStringValue(m_valueList->current());
3350 m_valueList->next();
3355 if (value->unit == CSSPrimitiveValue::CSS_STRING) {
3356 gridLineName = createPrimitiveStringValue(m_valueList->current());
3357 value = m_valueList->next();
3358 if (value && validUnit(value, FInteger) && value->fValue) {
3359 numericValue = createPrimitiveNumericValue(value);
3360 m_valueList->next();
3368 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridPosition()
3370 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3372 CSSParserValue* value = m_valueList->current();
3373 if (value->id == CSSValueAuto) {
3374 m_valueList->next();
3375 return cssValuePool().createIdentifierValue(CSSValueAuto);
3378 if (value->id != CSSValueSpan && value->unit == CSSPrimitiveValue::CSS_IDENT) {
3379 m_valueList->next();
3380 return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
3383 RefPtrWillBeRawPtr<CSSPrimitiveValue> numericValue = nullptr;
3384 RefPtrWillBeRawPtr<CSSPrimitiveValue> gridLineName = nullptr;
3385 bool hasSeenSpanKeyword = false;
3387 if (parseIntegerOrStringFromGridPosition(numericValue, gridLineName)) {
3388 value = m_valueList->current();
3389 if (value && value->id == CSSValueSpan) {
3390 hasSeenSpanKeyword = true;
3391 m_valueList->next();
3393 } else if (value->id == CSSValueSpan) {
3394 hasSeenSpanKeyword = true;
3395 if (m_valueList->next())
3396 parseIntegerOrStringFromGridPosition(numericValue, gridLineName);
3399 // Check that we have consumed all the value list. For shorthands, the parser will pass
3400 // the whole value list (including the opposite position).
3401 if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current()))
3404 // If we didn't parse anything, this is not a valid grid position.
3405 if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
3408 // Negative numbers are not allowed for span (but are for <integer>).
3409 if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
3412 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
3413 if (hasSeenSpanKeyword)
3414 values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
3416 values->append(numericValue.release());
3418 values->append(gridLineName.release());
3419 ASSERT(values->length());
3420 return values.release();
3423 static PassRefPtrWillBeRawPtr<CSSValue> gridMissingGridPositionValue(CSSValue* value)
3425 if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isString())
3428 return cssValuePool().createIdentifierValue(CSSValueAuto);
3431 bool CSSPropertyParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
3433 ShorthandScope scope(this, shorthandId);
3434 const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
3435 ASSERT(shorthand.length() == 2);
3437 RefPtrWillBeRawPtr<CSSValue> startValue = parseGridPosition();
3441 RefPtrWillBeRawPtr<CSSValue> endValue = nullptr;
3442 if (m_valueList->current()) {
3443 if (!isForwardSlashOperator(m_valueList->current()))
3446 if (!m_valueList->next())
3449 endValue = parseGridPosition();
3450 if (!endValue || m_valueList->current())
3453 endValue = gridMissingGridPositionValue(startValue.get());
3456 addProperty(shorthand.properties()[0], startValue, important);
3457 addProperty(shorthand.properties()[1], endValue, important);
3461 bool CSSPropertyParser::parseGridAreaShorthand(bool important)
3463 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3465 ShorthandScope scope(this, CSSPropertyGridArea);
3466 const StylePropertyShorthand& shorthand = gridAreaShorthand();
3467 ASSERT_UNUSED(shorthand, shorthand.length() == 4);
3469 RefPtrWillBeRawPtr<CSSValue> rowStartValue = parseGridPosition();
3473 RefPtrWillBeRawPtr<CSSValue> columnStartValue = nullptr;
3474 if (!parseSingleGridAreaLonghand(columnStartValue))
3477 RefPtrWillBeRawPtr<CSSValue> rowEndValue = nullptr;
3478 if (!parseSingleGridAreaLonghand(rowEndValue))
3481 RefPtrWillBeRawPtr<CSSValue> columnEndValue = nullptr;
3482 if (!parseSingleGridAreaLonghand(columnEndValue))
3485 if (!columnStartValue)
3486 columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
3489 rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
3491 if (!columnEndValue)
3492 columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
3494 addProperty(CSSPropertyGridRowStart, rowStartValue, important);
3495 addProperty(CSSPropertyGridColumnStart, columnStartValue, important);
3496 addProperty(CSSPropertyGridRowEnd, rowEndValue, important);
3497 addProperty(CSSPropertyGridColumnEnd, columnEndValue, important);
3501 bool CSSPropertyParser::parseSingleGridAreaLonghand(RefPtrWillBeRawPtr<CSSValue>& property)
3503 if (!m_valueList->current())
3506 if (!isForwardSlashOperator(m_valueList->current()))
3509 if (!m_valueList->next())
3512 property = parseGridPosition();
3516 void CSSPropertyParser::parseGridLineNames(CSSParserValueList* parserValueList, CSSValueList& valueList)
3518 ASSERT(parserValueList->current() && parserValueList->current()->unit == CSSParserValue::ValueList);
3520 CSSParserValueList* identList = parserValueList->current()->valueList;
3521 if (!identList->size()) {
3522 parserValueList->next();
3526 RefPtrWillBeRawPtr<CSSGridLineNamesValue> lineNames = CSSGridLineNamesValue::create();
3527 while (CSSParserValue* identValue = identList->current()) {
3528 ASSERT(identValue->unit == CSSPrimitiveValue::CSS_IDENT);
3529 RefPtrWillBeRawPtr<CSSPrimitiveValue> lineName = createPrimitiveStringValue(identValue);
3530 lineNames->append(lineName.release());
3533 valueList.append(lineNames.release());
3535 parserValueList->next();
3538 bool CSSPropertyParser::parseGridTrackList(CSSPropertyID propId, bool important)
3540 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3542 CSSParserValue* value = m_valueList->current();
3543 if (value->id == CSSValueNone) {
3544 if (m_valueList->next())
3547 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
3551 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
3552 // Handle leading <ident>*.
3553 value = m_valueList->current();
3554 if (value && value->unit == CSSParserValue::ValueList)
3555 parseGridLineNames(m_valueList.get(), *values);
3557 bool seenTrackSizeOrRepeatFunction = false;
3558 while (CSSParserValue* currentValue = m_valueList->current()) {
3559 if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "repeat(")) {
3560 if (!parseGridTrackRepeatFunction(*values))
3562 seenTrackSizeOrRepeatFunction = true;
3564 RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
3567 values->append(value);
3568 seenTrackSizeOrRepeatFunction = true;
3570 // This will handle the trailing <ident>* in the grammar.
3571 value = m_valueList->current();
3572 if (value && value->unit == CSSParserValue::ValueList)
3573 parseGridLineNames(m_valueList.get(), *values);
3576 // We should have found a <track-size> or else it is not a valid <track-list>
3577 if (!seenTrackSizeOrRepeatFunction)
3580 addProperty(propId, values.release(), important);
3584 bool CSSPropertyParser::parseGridTrackRepeatFunction(CSSValueList& list)
3586 CSSParserValueList* arguments = m_valueList->current()->function->args.get();
3587 if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1)))
3590 ASSERT_WITH_SECURITY_IMPLICATION(arguments->valueAt(0)->fValue > 0);
3591 size_t repetitions = arguments->valueAt(0)->fValue;
3592 RefPtrWillBeRawPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
3593 arguments->next(); // Skip the repetition count.
3594 arguments->next(); // Skip the comma.
3596 // Handle leading <ident>*.
3597 CSSParserValue* currentValue = arguments->current();
3598 if (currentValue && currentValue->unit == CSSParserValue::ValueList)
3599 parseGridLineNames(arguments, *repeatedValues);
3601 while (arguments->current()) {
3602 RefPtrWillBeRawPtr<CSSValue> trackSize = parseGridTrackSize(*arguments);
3606 repeatedValues->append(trackSize);
3608 // This takes care of any trailing <ident>* in the grammar.
3609 currentValue = arguments->current();
3610 if (currentValue && currentValue->unit == CSSParserValue::ValueList)
3611 parseGridLineNames(arguments, *repeatedValues);
3614 for (size_t i = 0; i < repetitions; ++i) {
3615 for (size_t j = 0; j < repeatedValues->length(); ++j)
3616 list.append(repeatedValues->itemWithoutBoundsCheck(j));
3619 // parseGridTrackSize iterated over the repeat arguments, move to the next value.
3620 m_valueList->next();
3625 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackSize(CSSParserValueList& inputList)
3627 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3629 CSSParserValue* currentValue = inputList.current();
3632 if (currentValue->id == CSSValueAuto)
3633 return cssValuePool().createIdentifierValue(CSSValueAuto);
3635 if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax(")) {
3636 // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
3637 CSSParserValueList* arguments = currentValue->function->args.get();
3638 if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
3641 RefPtrWillBeRawPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0));
3642 if (!minTrackBreadth)
3645 RefPtrWillBeRawPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2));
3646 if (!maxTrackBreadth)
3649 RefPtrWillBeRawPtr<CSSValueList> parsedArguments = CSSValueList::createCommaSeparated();
3650 parsedArguments->append(minTrackBreadth);
3651 parsedArguments->append(maxTrackBreadth);
3652 return CSSFunctionValue::create("minmax(", parsedArguments);
3655 return parseGridBreadth(currentValue);
3658 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseGridBreadth(CSSParserValue* currentValue)
3660 if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMaxContent)
3661 return cssValuePool().createIdentifierValue(currentValue->id);
3663 if (currentValue->unit == CSSPrimitiveValue::CSS_FR) {
3664 double flexValue = currentValue->fValue;
3666 // Fractional unit is a non-negative dimension.
3670 return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR);
3673 if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
3676 return createPrimitiveNumericValue(currentValue);
3679 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTemplateAreas()
3681 NamedGridAreaMap gridAreaMap;
3682 size_t rowCount = 0;
3683 size_t columnCount = 0;
3685 while (CSSParserValue* currentValue = m_valueList->current()) {
3686 if (currentValue->unit != CSSPrimitiveValue::CSS_STRING)
3689 String gridRowNames = currentValue->string;
3690 if (!gridRowNames.length())
3693 Vector<String> columnNames;
3694 gridRowNames.split(' ', columnNames);
3697 columnCount = columnNames.size();
3698 ASSERT(columnCount);
3699 } else if (columnCount != columnNames.size()) {
3700 // The declaration is invalid is all the rows don't have the number of columns.
3704 for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
3705 const String& gridAreaName = columnNames[currentCol];
3707 // Unamed areas are always valid (we consider them to be 1x1).
3708 if (gridAreaName == ".")
3711 // We handle several grid areas with the same name at once to simplify the validation code.
3712 size_t lookAheadCol;
3713 for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++lookAheadCol) {
3714 if (columnNames[lookAheadCol + 1] != gridAreaName)
3718 NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
3719 if (gridAreaIt == gridAreaMap.end()) {
3720 gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowCount), GridSpan(currentCol, lookAheadCol)));
3722 GridCoordinate& gridCoordinate = gridAreaIt->value;
3724 // The following checks test that the grid area is a single filled-in rectangle.
3725 // 1. The new row is adjacent to the previously parsed row.
3726 if (rowCount != gridCoordinate.rows.finalPositionIndex + 1)
3729 // 2. The new area starts at the same position as the previously parsed area.
3730 if (currentCol != gridCoordinate.columns.initialPositionIndex)
3733 // 3. The new area ends at the same position as the previously parsed area.
3734 if (lookAheadCol != gridCoordinate.columns.finalPositionIndex)
3737 ++gridCoordinate.rows.finalPositionIndex;
3739 currentCol = lookAheadCol;
3743 m_valueList->next();
3746 if (!rowCount || !columnCount)
3749 return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
3752 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseCounterContent(CSSParserValueList* args, bool counters)
3754 unsigned numArgs = args->size();
3755 if (counters && numArgs != 3 && numArgs != 5)
3757 if (!counters && numArgs != 1 && numArgs != 3)
3760 CSSParserValue* i = args->current();
3761 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
3763 RefPtrWillBeRawPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i);
3765 RefPtrWillBeRawPtr<CSSPrimitiveValue> separator = nullptr;
3767 separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING);
3770 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
3774 if (i->unit != CSSPrimitiveValue::CSS_STRING)
3777 separator = createPrimitiveStringValue(i);
3780 RefPtrWillBeRawPtr<CSSPrimitiveValue> listStyle = nullptr;
3782 if (!i) // Make the list style default decimal
3783 listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
3785 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
3789 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
3792 CSSValueID listStyleID = CSSValueInvalid;
3793 if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha))
3794 listStyleID = i->id;
3798 listStyle = cssValuePool().createIdentifierValue(listStyleID);
3801 return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
3804 bool CSSPropertyParser::parseClipShape(CSSPropertyID propId, bool important)
3806 CSSParserValue* value = m_valueList->current();
3807 CSSParserValueList* args = value->function->args.get();
3809 if (!equalIgnoringCase(value->function->name, "rect(") || !args)
3812 // rect(t, r, b, l) || rect(t r b l)
3813 if (args->size() != 4 && args->size() != 7)
3815 RefPtrWillBeRawPtr<Rect> rect = Rect::create();
3818 CSSParserValue* a = args->current();
3820 valid = a->id == CSSValueAuto || validUnit(a, FLength);
3823 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
3824 cssValuePool().createIdentifierValue(CSSValueAuto) :
3825 createPrimitiveNumericValue(a);
3827 rect->setTop(length);
3829 rect->setRight(length);
3831 rect->setBottom(length);
3833 rect->setLeft(length);
3835 if (a && args->size() == 7) {
3836 if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
3846 addProperty(propId, cssValuePool().createValue(rect.release()), important);
3847 m_valueList->next();
3853 static void completeBorderRadii(RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[4])
3859 radii[1] = radii[0];
3860 radii[2] = radii[0];
3862 radii[3] = radii[1];
3865 // FIXME: This should be refactored with CSSParser::parseBorderRadius.
3866 // CSSParser::parseBorderRadius contains support for some legacy radius construction.
3867 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseInsetRoundedCorners(PassRefPtrWillBeRawPtr<CSSBasicShapeInset> shape, CSSParserValueList* args)
3869 CSSParserValue* argument = args->next();
3874 CSSParserValueList radiusArguments;
3876 radiusArguments.addValue(*argument);
3877 argument = args->next();
3880 unsigned num = radiusArguments.size();
3881 if (!num || num > 9)
3884 // FIXME: Refactor completeBorderRadii and the array
3885 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
3887 // Zero initialize the array of raw pointers.
3888 memset(&radii, 0, sizeof(radii));
3891 unsigned indexAfterSlash = 0;
3892 for (unsigned i = 0; i < num; ++i) {
3893 CSSParserValue* value = radiusArguments.valueAt(i);
3894 if (value->unit == CSSParserValue::Operator) {
3895 if (value->iValue != '/')
3898 if (!i || indexAfterSlash || i + 1 == num)
3901 indexAfterSlash = i + 1;
3902 completeBorderRadii(radii[0]);
3906 if (i - indexAfterSlash >= 4)
3909 if (!validUnit(value, FLength | FPercent | FNonNeg))
3912 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
3914 if (!indexAfterSlash)
3915 radii[0][i] = radius;
3917 radii[1][i - indexAfterSlash] = radius.release();
3920 if (!indexAfterSlash) {
3921 completeBorderRadii(radii[0]);
3922 for (unsigned i = 0; i < 4; ++i)
3923 radii[1][i] = radii[0][i];
3925 completeBorderRadii(radii[1]);
3927 shape->setTopLeftRadius(createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()));
3928 shape->setTopRightRadius(createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()));
3929 shape->setBottomRightRadius(createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()));
3930 shape->setBottomLeftRadius(createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()));
3935 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeInset(CSSParserValueList* args)
3939 RefPtrWillBeRawPtr<CSSBasicShapeInset> shape = CSSBasicShapeInset::create();
3941 CSSParserValue* argument = args->current();
3942 WillBeHeapVector<RefPtrWillBeMember<CSSPrimitiveValue> > widthArguments;
3943 bool hasRoundedInset = false;
3946 if (argument->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(argument->string, "round")) {
3947 hasRoundedInset = true;
3951 Units unitFlags = FLength | FPercent;
3952 if (!validUnit(argument, unitFlags) || widthArguments.size() > 4)
3955 widthArguments.append(createPrimitiveNumericValue(argument));
3956 argument = args->next();
3959 switch (widthArguments.size()) {
3961 shape->updateShapeSize1Value(widthArguments[0].get());
3965 shape->updateShapeSize2Values(widthArguments[0].get(), widthArguments[1].get());
3969 shape->updateShapeSize3Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get());
3973 shape->updateShapeSize4Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get(), widthArguments[3].get());
3980 if (hasRoundedInset)
3981 return parseInsetRoundedCorners(shape, args);
3985 static bool isItemPositionKeyword(CSSValueID id)
3987 return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
3988 || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
3989 || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight;
3992 bool CSSPropertyParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important)
3994 // auto | baseline | stretch | [<item-position> && <overflow-position>? ]
3995 // <item-position> = center | start | end | self-start | self-end | flex-start | flex-end | left | right;
3996 // <overflow-position> = true | safe
3998 CSSParserValue* value = m_valueList->current();
4000 if (value->id == CSSValueAuto || value->id == CSSValueBaseline || value->id == CSSValueStretch) {
4001 if (m_valueList->next())
4004 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
4008 RefPtrWillBeRawPtr<CSSPrimitiveValue> position = nullptr;
4009 RefPtrWillBeRawPtr<CSSPrimitiveValue> overflowAlignmentKeyword = nullptr;
4010 if (isItemPositionKeyword(value->id)) {
4011 position = cssValuePool().createIdentifierValue(value->id);
4012 value = m_valueList->next();
4014 if (value->id == CSSValueTrue || value->id == CSSValueSafe)
4015 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
4019 } else if (value->id == CSSValueTrue || value->id == CSSValueSafe) {
4020 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
4021 value = m_valueList->next();
4023 if (isItemPositionKeyword(value->id))
4024 position = cssValuePool().createIdentifierValue(value->id);
4032 if (m_valueList->next())
4036 if (overflowAlignmentKeyword)
4037 addProperty(propId, createPrimitiveValuePair(position, overflowAlignmentKeyword), important);
4039 addProperty(propId, position.release(), important);
4044 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseShapeRadius(CSSParserValue* value)
4046 if (value->id == CSSValueClosestSide || value->id == CSSValueFarthestSide)
4047 return cssValuePool().createIdentifierValue(value->id);
4049 if (!validUnit(value, FLength | FPercent | FNonNeg))
4052 return createPrimitiveNumericValue(value);
4055 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeCircle(CSSParserValueList* args)
4060 // circle(radius at <position>)
4061 // circle(at <position>)
4062 // where position defines centerX and centerY using a CSS <position> data type.
4063 RefPtrWillBeRawPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
4065 for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
4066 // The call to parseFillPosition below should consume all of the
4067 // arguments except the first two. Thus, and index greater than one
4068 // indicates an invalid production.
4069 if (args->currentIndex() > 1)
4072 if (!args->currentIndex() && argument->id != CSSValueAt) {
4073 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
4074 shape->setRadius(radius);
4081 if (argument->id == CSSValueAt && args->next()) {
4082 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
4083 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
4084 parseFillPosition(args, centerX, centerY);
4085 if (centerX && centerY && !args->current()) {
4086 ASSERT(centerX->isPrimitiveValue());
4087 ASSERT(centerY->isPrimitiveValue());
4088 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
4089 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
4101 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeEllipse(CSSParserValueList* args)
4106 // ellipse(radiusX at <position>)
4107 // ellipse(radiusX radiusY)
4108 // ellipse(radiusX radiusY at <position>)
4109 // ellipse(at <position>)
4110 // where position defines centerX and centerY using a CSS <position> data type.
4111 RefPtrWillBeRawPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
4113 for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
4114 // The call to parseFillPosition below should consume all of the
4115 // arguments except the first three. Thus, an index greater than two
4116 // indicates an invalid production.
4117 if (args->currentIndex() > 2)
4120 if (args->currentIndex() < 2 && argument->id != CSSValueAt) {
4121 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
4122 if (!shape->radiusX())
4123 shape->setRadiusX(radius);
4125 shape->setRadiusY(radius);
4132 if (argument->id != CSSValueAt || !args->next()) // expecting ellipse(.. at <position>)
4134 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
4135 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
4136 parseFillPosition(args, centerX, centerY);
4137 if (!centerX || !centerY || args->current())
4140 ASSERT(centerX->isPrimitiveValue());
4141 ASSERT(centerY->isPrimitiveValue());
4142 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
4143 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
4149 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapePolygon(CSSParserValueList* args)
4153 unsigned size = args->size();
4157 RefPtrWillBeRawPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
4159 CSSParserValue* argument = args->current();
4160 if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
4161 shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
4163 if (!isComma(args->next()))
4166 argument = args->next();
4170 // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one
4171 if (!size || (size % 3) - 2)
4174 CSSParserValue* argumentX = argument;
4176 if (!validUnit(argumentX, FLength | FPercent))
4179 CSSParserValue* argumentY = args->next();
4180 if (!argumentY || !validUnit(argumentY, FLength | FPercent))
4183 RefPtrWillBeRawPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX);
4184 RefPtrWillBeRawPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY);
4186 shape->appendPoint(xLength.release(), yLength.release());
4188 CSSParserValue* commaOrNull = args->next();
4191 else if (!isComma(commaOrNull))
4194 argumentX = args->next();
4200 static bool isBoxValue(CSSValueID valueId)
4203 case CSSValueContentBox:
4204 case CSSValuePaddingBox:
4205 case CSSValueBorderBox:
4206 case CSSValueMarginBox:
4215 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseShapeProperty(CSSPropertyID propId)
4217 if (!RuntimeEnabledFeatures::cssShapesEnabled())
4220 CSSParserValue* value = m_valueList->current();
4221 CSSValueID valueId = value->id;
4223 if (valueId == CSSValueNone) {
4224 RefPtrWillBeRawPtr<CSSPrimitiveValue> keywordValue = parseValidPrimitive(valueId, value);
4225 m_valueList->next();
4226 return keywordValue.release();
4229 RefPtrWillBeRawPtr<CSSValue> imageValue = nullptr;
4230 if (valueId != CSSValueNone && parseFillImage(m_valueList.get(), imageValue)) {
4231 m_valueList->next();
4232 return imageValue.release();
4235 return parseBasicShapeAndOrBox();
4238 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBasicShapeAndOrBox()
4240 CSSParserValue* value = m_valueList->current();
4242 bool shapeFound = false;
4243 bool boxFound = false;
4246 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
4247 for (unsigned i = 0; i < 2; ++i) {
4250 valueId = value->id;
4251 if (value->unit == CSSParserValue::Function && !shapeFound) {
4252 // parseBasicShape already asks for the next value list item.
4253 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = parseBasicShape();
4256 list->append(shapeValue.release());
4258 } else if (isBoxValue(valueId) && !boxFound) {
4259 list->append(parseValidPrimitive(valueId, value));
4261 m_valueList->next();
4266 value = m_valueList->current();
4269 if (m_valueList->current())
4271 return list.release();
4274 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseBasicShape()
4276 CSSParserValue* value = m_valueList->current();
4277 ASSERT(value->unit == CSSParserValue::Function);
4278 CSSParserValueList* args = value->function->args.get();
4283 RefPtrWillBeRawPtr<CSSBasicShape> shape = nullptr;
4284 if (equalIgnoringCase(value->function->name, "circle("))
4285 shape = parseBasicShapeCircle(args);
4286 else if (equalIgnoringCase(value->function->name, "ellipse("))
4287 shape = parseBasicShapeEllipse(args);
4288 else if (equalIgnoringCase(value->function->name, "polygon("))
4289 shape = parseBasicShapePolygon(args);
4290 else if (equalIgnoringCase(value->function->name, "inset("))
4291 shape = parseBasicShapeInset(args);
4296 m_valueList->next();
4298 return cssValuePool().createValue(shape.release());
4301 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
4302 bool CSSPropertyParser::parseFont(bool important)
4304 // Let's check if there is an inherit or initial somewhere in the shorthand.
4305 for (unsigned i = 0; i < m_valueList->size(); ++i) {
4306 if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial)
4310 ShorthandScope scope(this, CSSPropertyFont);
4311 // Optional font-style, font-variant and font-weight.
4312 bool fontStyleParsed = false;
4313 bool fontVariantParsed = false;
4314 bool fontWeightParsed = false;
4315 CSSParserValue* value;
4316 while ((value = m_valueList->current())) {
4317 if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
4318 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
4319 fontStyleParsed = true;
4320 } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
4321 // Font variant in the shorthand is particular, it only accepts normal or small-caps.
4322 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important);
4323 fontVariantParsed = true;
4324 } else if (!fontWeightParsed && parseFontWeight(important))
4325 fontWeightParsed = true;
4328 m_valueList->next();
4334 if (!fontStyleParsed)
4335 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4336 if (!fontVariantParsed)
4337 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4338 if (!fontWeightParsed)
4339 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4341 // Now a font size _must_ come.
4342 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
4343 if (!parseFontSize(important))
4346 value = m_valueList->current();
4350 if (isForwardSlashOperator(value)) {
4351 // The line-height property.
4352 value = m_valueList->next();
4355 if (!parseLineHeight(important))
4358 addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4360 // Font family must come now.
4361 RefPtrWillBeRawPtr<CSSValue> parsedFamilyValue = parseFontFamily();
4362 if (!parsedFamilyValue)
4365 addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
4367 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
4368 // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
4369 // but we don't seem to support them at the moment. They should also be added here once implemented.
4370 if (m_valueList->current())
4376 class FontFamilyValueBuilder {
4377 DISALLOW_ALLOCATION();
4379 FontFamilyValueBuilder(CSSValueList* list)
4384 void add(const CSSParserString& string)
4386 if (!m_builder.isEmpty())
4387 m_builder.append(' ');
4389 if (string.is8Bit()) {
4390 m_builder.append(string.characters8(), string.length());
4394 m_builder.append(string.characters16(), string.length());
4399 if (m_builder.isEmpty())
4401 m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString()));
4406 StringBuilder m_builder;
4407 CSSValueList* m_list;
4410 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFontFamily()
4412 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
4413 CSSParserValue* value = m_valueList->current();
4415 FontFamilyValueBuilder familyBuilder(list.get());
4416 bool inFamily = false;
4419 CSSParserValue* nextValue = m_valueList->next();
4420 bool nextValBreaksFont = !nextValue ||
4421 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
4422 bool nextValIsFontName = nextValue &&
4423 ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
4424 (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
4426 bool valueIsKeyword = value->id == CSSValueInitial || value->id == CSSValueInherit || value->id == CSSValueDefault;
4427 if (valueIsKeyword && !inFamily) {
4428 if (nextValBreaksFont)
4429 value = m_valueList->next();
4430 else if (nextValIsFontName)
4435 if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
4437 familyBuilder.add(value->string);
4438 else if (nextValBreaksFont || !nextValIsFontName)
4439 list->append(cssValuePool().createIdentifierValue(value->id));
4441 familyBuilder.commit();
4442 familyBuilder.add(value->string);
4445 } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
4446 // Strings never share in a family name.
4448 familyBuilder.commit();
4449 list->append(cssValuePool().createFontFamilyValue(value->string));
4450 } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
4452 familyBuilder.add(value->string);
4453 else if (nextValBreaksFont || !nextValIsFontName)
4454 list->append(cssValuePool().createFontFamilyValue(value->string));
4456 familyBuilder.commit();
4457 familyBuilder.add(value->string);
4467 if (nextValBreaksFont) {
4468 value = m_valueList->next();
4469 familyBuilder.commit();
4472 else if (nextValIsFontName)
4477 familyBuilder.commit();
4479 if (!list->length())
4481 return list.release();
4484 bool CSSPropertyParser::parseLineHeight(bool important)
4486 CSSParserValue* value = m_valueList->current();
4487 CSSValueID id = value->id;
4488 bool validPrimitive = false;
4489 // normal | <number> | <length> | <percentage> | inherit
4490 if (id == CSSValueNormal)
4491 validPrimitive = true;
4493 validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
4494 if (validPrimitive && (!m_valueList->next() || inShorthand()))
4495 addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important);
4496 return validPrimitive;
4499 bool CSSPropertyParser::parseFontSize(bool important)
4501 CSSParserValue* value = m_valueList->current();
4502 CSSValueID id = value->id;
4503 bool validPrimitive = false;
4504 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
4505 if (id >= CSSValueXxSmall && id <= CSSValueLarger)
4506 validPrimitive = true;
4508 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
4509 if (validPrimitive && (!m_valueList->next() || inShorthand()))
4510 addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important);
4511 return validPrimitive;
4514 bool CSSPropertyParser::parseFontVariant(bool important)
4516 RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
4517 if (m_valueList->size() > 1)
4518 values = CSSValueList::createCommaSeparated();
4519 CSSParserValue* val;
4520 bool expectComma = false;
4521 while ((val = m_valueList->current())) {
4522 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue = nullptr;
4525 if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
4526 parsedValue = cssValuePool().createIdentifierValue(val->id);
4527 else if (val->id == CSSValueAll && !values) {
4528 // 'all' is only allowed in @font-face and with no other values. Make a value list to
4529 // indicate that we are in the @font-face case.
4530 values = CSSValueList::createCommaSeparated();
4531 parsedValue = cssValuePool().createIdentifierValue(val->id);
4533 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
4534 expectComma = false;
4535 m_valueList->next();
4542 m_valueList->next();
4545 values->append(parsedValue.release());
4547 addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
4552 if (values && values->length()) {
4553 m_hasFontFaceOnlyValues = true;
4554 addProperty(CSSPropertyFontVariant, values.release(), important);
4561 bool CSSPropertyParser::parseFontWeight(bool important)
4563 CSSParserValue* value = m_valueList->current();
4564 if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
4565 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important);
4568 if (validUnit(value, FInteger | FNonNeg, HTMLQuirksMode)) {
4569 int weight = static_cast<int>(value->fValue);
4570 if (!(weight % 100) && weight >= 100 && weight <= 900) {
4571 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1)), important);
4578 bool CSSPropertyParser::parseFontFaceSrcURI(CSSValueList* valueList)
4580 RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string)));
4582 CSSParserValue* value = m_valueList->next();
4584 valueList->append(uriValue.release());
4587 if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
4588 m_valueList->next();
4589 valueList->append(uriValue.release());
4593 if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format("))
4596 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
4597 // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
4598 CSSParserValueList* args = value->function->args.get();
4599 if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
4601 uriValue->setFormat(args->current()->string);
4602 valueList->append(uriValue.release());
4603 value = m_valueList->next();
4604 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
4605 m_valueList->next();
4609 bool CSSPropertyParser::parseFontFaceSrcLocal(CSSValueList* valueList)
4611 CSSParserValueList* args = m_valueList->current()->function->args.get();
4612 if (!args || !args->size())
4615 if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING)
4616 valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string));
4617 else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
4618 StringBuilder builder;
4619 for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) {
4620 if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
4622 if (!builder.isEmpty())
4623 builder.append(' ');
4624 builder.append(localValue->string);
4626 valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
4630 if (CSSParserValue* value = m_valueList->next()) {
4631 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
4632 m_valueList->next();
4637 bool CSSPropertyParser::parseFontFaceSrc()
4639 RefPtrWillBeRawPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
4641 while (CSSParserValue* value = m_valueList->current()) {
4642 if (value->unit == CSSPrimitiveValue::CSS_URI) {
4643 if (!parseFontFaceSrcURI(values.get()))
4645 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) {
4646 if (!parseFontFaceSrcLocal(values.get()))
4651 if (!values->length())
4654 addProperty(CSSPropertySrc, values.release(), m_important);
4655 m_valueList->next();
4659 bool CSSPropertyParser::parseFontFaceUnicodeRange()
4661 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
4662 bool failed = false;
4663 bool operatorExpected = false;
4664 for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
4665 if (operatorExpected) {
4666 if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
4671 if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
4676 String rangeString = m_valueList->current()->string;
4679 unsigned length = rangeString.length();
4687 while (i < length) {
4688 UChar c = rangeString[i];
4689 if (c == '-' || c == '?')
4692 if (c >= '0' && c <= '9')
4694 else if (c >= 'A' && c <= 'F')
4695 from += 10 + c - 'A';
4696 else if (c >= 'a' && c <= 'f')
4697 from += 10 + c - 'a';
4709 else if (rangeString[i] == '?') {
4711 while (i < length && rangeString[i] == '?') {
4718 to = from + span - 1;
4720 if (length < i + 2) {
4725 while (i < length) {
4726 UChar c = rangeString[i];
4728 if (c >= '0' && c <= '9')
4730 else if (c >= 'A' && c <= 'F')
4732 else if (c >= 'a' && c <= 'f')
4744 values->append(CSSUnicodeRangeValue::create(from, to));
4746 if (failed || !values->length())
4748 addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
4752 // Returns the number of characters which form a valid double
4753 // and are terminated by the given terminator character
4754 template <typename CharacterType>
4755 static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
4757 int length = end - string;
4761 bool decimalMarkSeen = false;
4762 int processedLength = 0;
4764 for (int i = 0; i < length; ++i) {
4765 if (string[i] == terminator) {
4766 processedLength = i;
4769 if (!isASCIIDigit(string[i])) {
4770 if (!decimalMarkSeen && string[i] == '.')
4771 decimalMarkSeen = true;
4777 if (decimalMarkSeen && processedLength == 1)
4780 return processedLength;
4783 // Returns the number of characters consumed for parsing a valid double
4784 // terminated by the given terminator character
4785 template <typename CharacterType>
4786 static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value)
4788 int length = checkForValidDouble(string, end, terminator);
4793 double localValue = 0;
4795 // The consumed characters here are guaranteed to be
4796 // ASCII digits with or without a decimal mark
4797 for (; position < length; ++position) {
4798 if (string[position] == '.')
4800 localValue = localValue * 10 + string[position] - '0';
4803 if (++position == length) {
4808 double fraction = 0;
4811 while (position < length && scale < MAX_SCALE) {
4812 fraction = fraction * 10 + string[position++] - '0';
4816 value = localValue + fraction / scale;
4820 template <typename CharacterType>
4821 static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
4823 const CharacterType* current = string;
4824 double localValue = 0;
4825 bool negative = false;
4826 while (current != end && isHTMLSpace<CharacterType>(*current))
4828 if (current != end && *current == '-') {
4832 if (current == end || !isASCIIDigit(*current))
4834 while (current != end && isASCIIDigit(*current)) {
4835 double newValue = localValue * 10 + *current++ - '0';
4836 if (newValue >= 255) {
4837 // Clamp values at 255.
4839 while (current != end && isASCIIDigit(*current))
4843 localValue = newValue;
4849 if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
4852 if (*current == '.') {
4853 // We already parsed the integral part, try to parse
4854 // the fraction part of the percentage value.
4855 double percentage = 0;
4856 int numCharactersParsed = parseDouble(current, end, '%', percentage);
4857 if (!numCharactersParsed)
4859 current += numCharactersParsed;
4860 if (*current != '%')
4862 localValue += percentage;
4865 if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
4868 if (*current == '%') {
4869 expect = CSSPrimitiveValue::CSS_PERCENTAGE;
4870 localValue = localValue / 100.0 * 256.0;
4871 // Clamp values at 255 for percentages over 100%
4872 if (localValue > 255)
4876 expect = CSSPrimitiveValue::CSS_NUMBER;
4878 while (current != end && isHTMLSpace<CharacterType>(*current))
4880 if (current == end || *current++ != terminator)
4882 // Clamp negative values at zero.
4883 value = negative ? 0 : static_cast<int>(localValue);
4888 template <typename CharacterType>
4889 static inline bool isTenthAlpha(const CharacterType* string, const int length)
4892 if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
4896 if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
4902 template <typename CharacterType>
4903 static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
4905 while (string != end && isHTMLSpace<CharacterType>(*string))
4908 bool negative = false;
4910 if (string != end && *string == '-') {
4917 int length = end - string;
4921 if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
4924 if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
4925 if (checkForValidDouble(string, end, terminator)) {
4926 value = negative ? 0 : 255;
4933 if (length == 2 && string[0] != '.') {
4934 value = !negative && string[0] == '1' ? 255 : 0;
4939 if (isTenthAlpha(string, length - 1)) {
4940 static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
4941 value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
4947 if (!parseDouble(string, end, terminator, alpha))
4949 value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
4954 template <typename CharacterType>
4955 static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
4959 return characters[4] == '('
4960 && isASCIIAlphaCaselessEqual(characters[0], 'r')
4961 && isASCIIAlphaCaselessEqual(characters[1], 'g')
4962 && isASCIIAlphaCaselessEqual(characters[2], 'b')
4963 && isASCIIAlphaCaselessEqual(characters[3], 'a');
4966 template <typename CharacterType>
4967 static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
4971 return characters[3] == '('
4972 && isASCIIAlphaCaselessEqual(characters[0], 'r')
4973 && isASCIIAlphaCaselessEqual(characters[1], 'g')
4974 && isASCIIAlphaCaselessEqual(characters[2], 'b');
4977 template <typename CharacterType>
4978 static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length , bool strict)
4980 CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
4982 if (!strict && length >= 3) {
4983 if (characters[0] == '#') {
4984 if (Color::parseHexColor(characters + 1, length - 1, rgb))
4987 if (Color::parseHexColor(characters, length, rgb))
4992 // Try rgba() syntax.
4993 if (mightBeRGBA(characters, length)) {
4994 const CharacterType* current = characters + 5;
4995 const CharacterType* end = characters + length;
5001 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
5003 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
5005 if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
5007 if (!parseAlphaValue(current, end, ')', alpha))
5011 rgb = makeRGBA(red, green, blue, alpha);
5015 // Try rgb() syntax.
5016 if (mightBeRGB(characters, length)) {
5017 const CharacterType* current = characters + 4;
5018 const CharacterType* end = characters + length;
5022 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
5024 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
5026 if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
5030 rgb = makeRGB(red, green, blue);
5037 template<typename StringType>
5038 bool CSSPropertyParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict)
5040 unsigned length = name.length();
5047 parseResult = fastParseColorInternal(rgb, name.characters8(), length, strict);
5049 parseResult = fastParseColorInternal(rgb, name.characters16(), length, strict);
5054 // Try named colors.
5056 if (!tc.setNamedColor(name))
5062 template bool CSSPropertyParser::fastParseColor(RGBA32&, const String&, bool strict);
5064 inline double CSSPropertyParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc)
5066 const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue;
5067 if (releaseCalc == ReleaseParsedCalcValue)
5068 m_parsedCalculation.release();
5072 bool CSSPropertyParser::isCalculation(CSSParserValue* value)
5074 return (value->unit == CSSParserValue::Function)
5075 && (equalIgnoringCase(value->function->name, "calc(")
5076 || equalIgnoringCase(value->function->name, "-webkit-calc(")
5077 || equalIgnoringCase(value->function->name, "-webkit-min(")
5078 || equalIgnoringCase(value->function->name, "-webkit-max("));
5081 inline int CSSPropertyParser::colorIntFromValue(CSSParserValue* v)
5085 if (m_parsedCalculation)
5086 isPercent = m_parsedCalculation->category() == CalcPercent;
5088 isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
5090 const double value = parsedDouble(v, ReleaseParsedCalcValue);
5098 return static_cast<int>(value * 256.0 / 100.0);
5104 return static_cast<int>(value);
5107 bool CSSPropertyParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
5109 CSSParserValueList* args = value->function->args.get();
5110 CSSParserValue* v = args->current();
5111 Units unitType = FUnknown;
5112 // Get the first value and its type
5113 if (validUnit(v, FInteger, HTMLStandardMode))
5114 unitType = FInteger;
5115 else if (validUnit(v, FPercent, HTMLStandardMode))
5116 unitType = FPercent;
5120 colorArray[0] = colorIntFromValue(v);
5121 for (int i = 1; i < 3; i++) {
5123 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5126 if (!validUnit(v, unitType, HTMLStandardMode))
5128 colorArray[i] = colorIntFromValue(v);
5132 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5135 if (!validUnit(v, FNumber, HTMLStandardMode))
5137 const double value = parsedDouble(v, ReleaseParsedCalcValue);
5138 // Convert the floating pointer number of alpha to an integer in the range [0, 256),
5139 // with an equal distribution across all 256 values.
5140 colorArray[3] = static_cast<int>(max(0.0, min(1.0, value)) * nextafter(256.0, 0.0));
5145 // The CSS3 specification defines the format of a HSL color as
5146 // hsl(<number>, <percent>, <percent>)
5147 // and with alpha, the format is
5148 // hsla(<number>, <percent>, <percent>, <number>)
5149 // The first value, HUE, is in an angle with a value between 0 and 360
5150 bool CSSPropertyParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
5152 CSSParserValueList* args = value->function->args.get();
5153 CSSParserValue* v = args->current();
5154 // Get the first value
5155 if (!validUnit(v, FNumber, HTMLStandardMode))
5157 // normalize the Hue value and change it to be between 0 and 1.0
5158 colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0;
5159 for (int i = 1; i < 3; i++) {
5161 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5164 if (!validUnit(v, FPercent, HTMLStandardMode))
5166 colorArray[i] = max(0.0, min(100.0, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0
5170 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5173 if (!validUnit(v, FNumber, HTMLStandardMode))
5175 colorArray[3] = max(0.0, min(1.0, parsedDouble(v, ReleaseParsedCalcValue)));
5180 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseColor(CSSParserValue* value)
5182 RGBA32 c = Color::transparent;
5183 if (!parseColorFromValue(value ? value : m_valueList->current(), c))
5185 return cssValuePool().createColorValue(c);
5188 bool CSSPropertyParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
5190 if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
5191 && value->fValue >= 0. && value->fValue < 1000000.) {
5192 String str = String::format("%06d", static_cast<int>((value->fValue+.5)));
5193 // FIXME: This should be strict parsing for SVG as well.
5194 if (!fastParseColor(c, str, !inQuirksMode()))
5196 } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
5197 value->unit == CSSPrimitiveValue::CSS_IDENT ||
5198 (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
5199 if (!fastParseColor(c, value->string, !inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
5201 } else if (value->unit == CSSParserValue::Function &&
5202 value->function->args != 0 &&
5203 value->function->args->size() == 5 /* rgb + two commas */ &&
5204 equalIgnoringCase(value->function->name, "rgb(")) {
5206 if (!parseColorParameters(value, colorValues, false))
5208 c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
5210 if (value->unit == CSSParserValue::Function &&
5211 value->function->args != 0 &&
5212 value->function->args->size() == 7 /* rgba + three commas */ &&
5213 equalIgnoringCase(value->function->name, "rgba(")) {
5215 if (!parseColorParameters(value, colorValues, true))
5217 c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
5218 } else if (value->unit == CSSParserValue::Function &&
5219 value->function->args != 0 &&
5220 value->function->args->size() == 5 /* hsl + two commas */ &&
5221 equalIgnoringCase(value->function->name, "hsl(")) {
5222 double colorValues[3];
5223 if (!parseHSLParameters(value, colorValues, false))
5225 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
5226 } else if (value->unit == CSSParserValue::Function &&
5227 value->function->args != 0 &&
5228 value->function->args->size() == 7 /* hsla + three commas */ &&
5229 equalIgnoringCase(value->function->name, "hsla(")) {
5230 double colorValues[4];
5231 if (!parseHSLParameters(value, colorValues, true))
5233 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
5241 // This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return)
5242 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
5243 class ShadowParseContext {
5246 ShadowParseContext(CSSPropertyID prop, CSSPropertyParser* parser)
5252 , allowSpread(false)
5254 , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
5259 bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
5263 // Handle the ,, case gracefully by doing nothing.
5264 if (x || y || blur || spread || color || style) {
5266 values = CSSValueList::createCommaSeparated();
5268 // Construct the current shadow value and add it to the list.
5269 values->append(CSSShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
5272 // Now reset for the next shadow value.
5285 allowSpread = false;
5286 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5289 void commitLength(CSSParserValue* v)
5291 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
5300 } else if (allowY) {
5305 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5307 } else if (allowBlur) {
5308 blur = val.release();
5310 allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5311 } else if (allowSpread) {
5312 spread = val.release();
5313 allowSpread = false;
5317 void commitColor(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val)
5326 allowSpread = false;
5327 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5331 void commitStyle(CSSParserValue* v)
5333 style = cssValuePool().createIdentifierValue(v->id);
5339 allowSpread = false;
5344 CSSPropertyID property;
5345 CSSPropertyParser* m_parser;
5347 RefPtrWillBeMember<CSSValueList> values;
5348 RefPtrWillBeMember<CSSPrimitiveValue> x;
5349 RefPtrWillBeMember<CSSPrimitiveValue> y;
5350 RefPtrWillBeMember<CSSPrimitiveValue> blur;
5351 RefPtrWillBeMember<CSSPrimitiveValue> spread;
5352 RefPtrWillBeMember<CSSPrimitiveValue> style;
5353 RefPtrWillBeMember<CSSPrimitiveValue> color;
5360 bool allowStyle; // inset or not.
5364 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId)
5366 ShadowParseContext context(propId, this);
5367 CSSParserValue* val;
5368 while ((val = valueList->current())) {
5369 // Check for a comma break first.
5370 if (val->unit == CSSParserValue::Operator) {
5371 if (val->iValue != ',' || !context.allowBreak) {
5372 // Other operators aren't legal or we aren't done with the current shadow
5373 // value. Treat as invalid.
5376 // The value is good. Commit it.
5377 context.commitValue();
5378 } else if (validUnit(val, FLength, HTMLStandardMode)) {
5379 // We required a length and didn't get one. Invalid.
5380 if (!context.allowLength())
5383 // Blur radius must be non-negative.
5384 if (context.allowBlur && !validUnit(val, FLength | FNonNeg, HTMLStandardMode))
5387 // A length is allowed here. Construct the value and add it.
5388 context.commitLength(val);
5389 } else if (val->id == CSSValueInset) {
5390 if (!context.allowStyle)
5393 context.commitStyle(val);
5395 // The only other type of value that's ok is a color value.
5396 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedColor = nullptr;
5397 bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu
5398 || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode())
5399 || val->id == CSSValueCurrentcolor);
5401 if (!context.allowColor)
5403 parsedColor = cssValuePool().createIdentifierValue(val->id);
5407 // It's not built-in. Try to parse it as a color.
5408 parsedColor = parseColor(val);
5410 if (!parsedColor || !context.allowColor)
5411 return nullptr; // This value is not a color or length and is invalid or
5412 // it is a color, but a color isn't allowed at this point.
5414 context.commitColor(parsedColor.release());
5420 if (context.allowBreak) {
5421 context.commitValue();
5422 if (context.values && context.values->length())
5423 return context.values.release();
5429 bool CSSPropertyParser::parseReflect(CSSPropertyID propId, bool important)
5431 // box-reflect: <direction> <offset> <mask>
5433 // Direction comes first.
5434 CSSParserValue* val = m_valueList->current();
5435 RefPtrWillBeRawPtr<CSSPrimitiveValue> direction = nullptr;
5441 direction = cssValuePool().createIdentifierValue(val->id);
5447 // The offset comes next.
5448 val = m_valueList->next();
5449 RefPtrWillBeRawPtr<CSSPrimitiveValue> offset = nullptr;
5451 offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
5453 if (!validUnit(val, FLength | FPercent))
5455 offset = createPrimitiveNumericValue(val);
5458 // Now for the mask.
5459 RefPtrWillBeRawPtr<CSSValue> mask = nullptr;
5460 val = m_valueList->next();
5462 mask = parseBorderImage(propId);
5467 RefPtrWillBeRawPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction.release(), offset.release(), mask.release());
5468 addProperty(propId, reflectValue.release(), important);
5469 m_valueList->next();
5473 bool CSSPropertyParser::parseFlex(CSSParserValueList* args, bool important)
5475 if (!args || !args->size() || args->size() > 3)
5477 static const double unsetValue = -1;
5478 double flexGrow = unsetValue;
5479 double flexShrink = unsetValue;
5480 RefPtrWillBeRawPtr<CSSPrimitiveValue> flexBasis = nullptr;
5482 while (CSSParserValue* arg = args->current()) {
5483 if (validUnit(arg, FNumber | FNonNeg)) {
5484 if (flexGrow == unsetValue)
5485 flexGrow = arg->fValue;
5486 else if (flexShrink == unsetValue)
5487 flexShrink = arg->fValue;
5488 else if (!arg->fValue) {
5489 // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
5490 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
5492 // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
5495 } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg)))
5496 flexBasis = parseValidPrimitive(arg->id, arg);
5498 // Not a valid arg for flex.
5504 if (flexGrow == unsetValue)
5506 if (flexShrink == unsetValue)
5509 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
5511 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
5512 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
5513 addProperty(CSSPropertyFlexBasis, flexBasis, important);
5517 bool CSSPropertyParser::parseObjectPosition(bool important)
5519 RefPtrWillBeRawPtr<CSSValue> xValue = nullptr;
5520 RefPtrWillBeRawPtr<CSSValue> yValue = nullptr;
5521 parseFillPosition(m_valueList.get(), xValue, yValue);
5522 if (!xValue || !yValue)
5525 CSSPropertyObjectPosition,
5526 createPrimitiveValuePair(toCSSPrimitiveValue(xValue.get()), toCSSPrimitiveValue(yValue.get()), Pair::KeepIdenticalValues),
5531 class BorderImageParseContext {
5534 BorderImageParseContext()
5535 : m_canAdvance(false)
5536 , m_allowCommit(true)
5537 , m_allowImage(true)
5538 , m_allowImageSlice(true)
5539 , m_allowRepeat(true)
5540 , m_allowForwardSlashOperator(false)
5541 , m_requireWidth(false)
5542 , m_requireOutset(false)
5545 bool canAdvance() const { return m_canAdvance; }
5546 void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
5548 bool allowCommit() const { return m_allowCommit; }
5549 bool allowImage() const { return m_allowImage; }
5550 bool allowImageSlice() const { return m_allowImageSlice; }
5551 bool allowRepeat() const { return m_allowRepeat; }
5552 bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; }
5554 bool requireWidth() const { return m_requireWidth; }
5555 bool requireOutset() const { return m_requireOutset; }
5557 void commitImage(PassRefPtrWillBeRawPtr<CSSValue> image)
5560 m_canAdvance = true;
5561 m_allowCommit = true;
5562 m_allowImage = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
5563 m_allowImageSlice = !m_imageSlice;
5564 m_allowRepeat = !m_repeat;
5566 void commitImageSlice(PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> slice)
5568 m_imageSlice = slice;
5569 m_canAdvance = true;
5570 m_allowCommit = m_allowForwardSlashOperator = true;
5571 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
5572 m_allowImage = !m_image;
5573 m_allowRepeat = !m_repeat;
5575 void commitForwardSlashOperator()
5577 m_canAdvance = true;
5578 m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowForwardSlashOperator = false;
5579 if (!m_borderSlice) {
5580 m_requireWidth = true;
5581 m_requireOutset = false;
5583 m_requireOutset = true;
5584 m_requireWidth = false;
5587 void commitBorderWidth(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> slice)
5589 m_borderSlice = slice;
5590 m_canAdvance = true;
5591 m_allowCommit = m_allowForwardSlashOperator = true;
5592 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
5593 m_allowImage = !m_image;
5594 m_allowRepeat = !m_repeat;
5596 void commitBorderOutset(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> outset)
5599 m_canAdvance = true;
5600 m_allowCommit = true;
5601 m_allowImageSlice = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
5602 m_allowImage = !m_image;
5603 m_allowRepeat = !m_repeat;
5605 void commitRepeat(PassRefPtrWillBeRawPtr<CSSValue> repeat)
5608 m_canAdvance = true;
5609 m_allowCommit = true;
5610 m_allowRepeat = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
5611 m_allowImageSlice = !m_imageSlice;
5612 m_allowImage = !m_image;
5615 PassRefPtrWillBeRawPtr<CSSValue> commitCSSValue()
5617 return createBorderImageValue(m_image, m_imageSlice.get(), m_borderSlice.get(), m_outset.get(), m_repeat.get());
5620 void commitMaskBoxImage(CSSPropertyParser* parser, bool important)
5622 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSource, parser, m_image, important);
5623 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSlice, parser, m_imageSlice.get(), important);
5624 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageWidth, parser, m_borderSlice.get(), important);
5625 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageOutset, parser, m_outset.get(), important);
5626 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageRepeat, parser, m_repeat.get(), important);
5629 void commitBorderImage(CSSPropertyParser* parser, bool important)
5631 commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
5632 commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice.get(), important);
5633 commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice.get(), important);
5634 commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset.get(), important);
5635 commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important);
5638 void commitBorderImageProperty(CSSPropertyID propId, CSSPropertyParser* parser, PassRefPtrWillBeRawPtr<CSSValue> value, bool important)
5641 parser->addProperty(propId, value, important);
5643 parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true);
5646 static bool buildFromParser(CSSPropertyParser&, CSSPropertyID, BorderImageParseContext&);
5652 bool m_allowImageSlice;
5654 bool m_allowForwardSlashOperator;
5656 bool m_requireWidth;
5657 bool m_requireOutset;
5659 RefPtrWillBeMember<CSSValue> m_image;
5660 RefPtrWillBeMember<CSSBorderImageSliceValue> m_imageSlice;
5661 RefPtrWillBeMember<CSSPrimitiveValue> m_borderSlice;
5662 RefPtrWillBeMember<CSSPrimitiveValue> m_outset;
5664 RefPtrWillBeMember<CSSValue> m_repeat;
5667 bool BorderImageParseContext::buildFromParser(CSSPropertyParser& parser, CSSPropertyID propId, BorderImageParseContext& context)
5669 CSSPropertyParser::ShorthandScope scope(&parser, propId);
5670 while (CSSParserValue* val = parser.m_valueList->current()) {
5671 context.setCanAdvance(false);
5673 if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(val))
5674 context.commitForwardSlashOperator();
5676 if (!context.canAdvance() && context.allowImage()) {
5677 if (val->unit == CSSPrimitiveValue::CSS_URI) {
5678 context.commitImage(CSSImageValue::create(val->string, parser.m_context.completeURL(val->string)));
5679 } else if (isGeneratedImageValue(val)) {
5680 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
5681 if (parser.parseGeneratedImage(parser.m_valueList.get(), value))
5682 context.commitImage(value.release());
5685 } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
5686 RefPtrWillBeRawPtr<CSSValue> value = parser.parseImageSet(parser.m_valueList.get());
5688 context.commitImage(value.release());
5691 } else if (val->id == CSSValueNone)
5692 context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone));
5695 if (!context.canAdvance() && context.allowImageSlice()) {
5696 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> imageSlice = nullptr;
5697 if (parser.parseBorderImageSlice(propId, imageSlice))
5698 context.commitImageSlice(imageSlice.release());
5701 if (!context.canAdvance() && context.allowRepeat()) {
5702 RefPtrWillBeRawPtr<CSSValue> repeat = nullptr;
5703 if (parser.parseBorderImageRepeat(repeat))
5704 context.commitRepeat(repeat.release());
5707 if (!context.canAdvance() && context.requireWidth()) {
5708 RefPtrWillBeRawPtr<CSSPrimitiveValue> borderSlice = nullptr;
5709 if (parser.parseBorderImageWidth(borderSlice))
5710 context.commitBorderWidth(borderSlice.release());
5713 if (!context.canAdvance() && context.requireOutset()) {
5714 RefPtrWillBeRawPtr<CSSPrimitiveValue> borderOutset = nullptr;
5715 if (parser.parseBorderImageOutset(borderOutset))
5716 context.commitBorderOutset(borderOutset.release());
5719 if (!context.canAdvance())
5722 parser.m_valueList->next();
5725 return context.allowCommit();
5728 bool CSSPropertyParser::parseBorderImageShorthand(CSSPropertyID propId, bool important)
5730 BorderImageParseContext context;
5731 if (BorderImageParseContext::buildFromParser(*this, propId, context)) {
5733 case CSSPropertyWebkitMaskBoxImage:
5734 context.commitMaskBoxImage(this, important);
5736 case CSSPropertyBorderImage:
5737 context.commitBorderImage(this, important);
5740 ASSERT_NOT_REACHED();
5747 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBorderImage(CSSPropertyID propId)
5749 BorderImageParseContext context;
5750 if (BorderImageParseContext::buildFromParser(*this, propId, context)) {
5751 return context.commitCSSValue();
5756 static bool isBorderImageRepeatKeyword(int id)
5758 return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
5761 bool CSSPropertyParser::parseBorderImageRepeat(RefPtrWillBeRawPtr<CSSValue>& result)
5763 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstValue = nullptr;
5764 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondValue = nullptr;
5765 CSSParserValue* val = m_valueList->current();
5768 if (isBorderImageRepeatKeyword(val->id))
5769 firstValue = cssValuePool().createIdentifierValue(val->id);
5773 val = m_valueList->next();
5775 if (isBorderImageRepeatKeyword(val->id))
5776 secondValue = cssValuePool().createIdentifierValue(val->id);
5777 else if (!inShorthand()) {
5778 // If we're not parsing a shorthand then we are invalid.
5781 // We need to rewind the value list, so that when its advanced we'll
5782 // end up back at this value.
5783 m_valueList->previous();
5784 secondValue = firstValue;
5787 secondValue = firstValue;
5789 result = createPrimitiveValuePair(firstValue, secondValue);
5793 class BorderImageSliceParseContext {
5796 BorderImageSliceParseContext(CSSPropertyParser* parser)
5798 , m_allowNumber(true)
5800 , m_allowFinalCommit(false)
5804 bool allowNumber() const { return m_allowNumber; }
5805 bool allowFill() const { return m_allowFill; }
5806 bool allowFinalCommit() const { return m_allowFinalCommit; }
5807 CSSPrimitiveValue* top() const { return m_top.get(); }
5809 void commitNumber(CSSParserValue* v)
5811 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
5823 m_allowNumber = !m_left;
5824 m_allowFinalCommit = true;
5827 void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; }
5829 PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
5831 // We need to clone and repeat values for any omissions.
5845 // Now build a rect value to hold all four of our primitive values.
5846 RefPtrWillBeRawPtr<Quad> quad = Quad::create();
5847 quad->setTop(m_top);
5848 quad->setRight(m_right);
5849 quad->setBottom(m_bottom);
5850 quad->setLeft(m_left);
5852 // Make our new border image value now.
5853 return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill);
5857 CSSPropertyParser* m_parser;
5861 bool m_allowFinalCommit;
5863 RefPtrWillBeMember<CSSPrimitiveValue> m_top;
5864 RefPtrWillBeMember<CSSPrimitiveValue> m_right;
5865 RefPtrWillBeMember<CSSPrimitiveValue> m_bottom;
5866 RefPtrWillBeMember<CSSPrimitiveValue> m_left;
5871 bool CSSPropertyParser::parseBorderImageSlice(CSSPropertyID propId, RefPtrWillBeRawPtr<CSSBorderImageSliceValue>& result)
5873 BorderImageSliceParseContext context(this);
5874 CSSParserValue* val;
5875 while ((val = m_valueList->current())) {
5876 // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
5877 if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, HTMLStandardMode)) {
5878 context.commitNumber(val);
5879 } else if (context.allowFill() && val->id == CSSValueFill)
5880 context.commitFill();
5881 else if (!inShorthand()) {
5882 // If we're not parsing a shorthand then we are invalid.
5885 if (context.allowFinalCommit()) {
5886 // We're going to successfully parse, but we don't want to consume this token.
5887 m_valueList->previous();
5891 m_valueList->next();
5894 if (context.allowFinalCommit()) {
5895 // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
5896 // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
5897 if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
5898 context.commitFill();
5900 // Need to fully commit as a single value.
5901 result = context.commitBorderImageSlice();
5908 class BorderImageQuadParseContext {
5911 BorderImageQuadParseContext(CSSPropertyParser* parser)
5913 , m_allowNumber(true)
5914 , m_allowFinalCommit(false)
5917 bool allowNumber() const { return m_allowNumber; }
5918 bool allowFinalCommit() const { return m_allowFinalCommit; }
5919 CSSPrimitiveValue* top() const { return m_top.get(); }
5921 void commitNumber(CSSParserValue* v)
5923 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = nullptr;
5924 if (v->id == CSSValueAuto)
5925 val = cssValuePool().createIdentifierValue(v->id);
5927 val = m_parser->createPrimitiveNumericValue(v);
5940 m_allowNumber = !m_left;
5941 m_allowFinalCommit = true;
5944 void setAllowFinalCommit() { m_allowFinalCommit = true; }
5945 void setTop(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val) { m_top = val; }
5947 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> commitBorderImageQuad()
5949 // We need to clone and repeat values for any omissions.
5963 // Now build a quad value to hold all four of our primitive values.
5964 RefPtrWillBeRawPtr<Quad> quad = Quad::create();
5965 quad->setTop(m_top);
5966 quad->setRight(m_right);
5967 quad->setBottom(m_bottom);
5968 quad->setLeft(m_left);
5970 // Make our new value now.
5971 return cssValuePool().createValue(quad.release());
5975 CSSPropertyParser* m_parser;
5978 bool m_allowFinalCommit;
5980 RefPtrWillBeMember<CSSPrimitiveValue> m_top;
5981 RefPtrWillBeMember<CSSPrimitiveValue> m_right;
5982 RefPtrWillBeMember<CSSPrimitiveValue> m_bottom;
5983 RefPtrWillBeMember<CSSPrimitiveValue> m_left;
5986 bool CSSPropertyParser::parseBorderImageQuad(Units validUnits, RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
5988 BorderImageQuadParseContext context(this);
5989 CSSParserValue* val;
5990 while ((val = m_valueList->current())) {
5991 if (context.allowNumber() && (validUnit(val, validUnits, HTMLStandardMode) || val->id == CSSValueAuto)) {
5992 context.commitNumber(val);
5993 } else if (!inShorthand()) {
5994 // If we're not parsing a shorthand then we are invalid.
5997 if (context.allowFinalCommit())
5998 m_valueList->previous(); // The shorthand loop will advance back to this point.
6001 m_valueList->next();
6004 if (context.allowFinalCommit()) {
6005 // Need to fully commit as a single value.
6006 result = context.commitBorderImageQuad();
6012 bool CSSPropertyParser::parseBorderImageWidth(RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
6014 return parseBorderImageQuad(FLength | FNumber | FNonNeg | FPercent, result);
6017 bool CSSPropertyParser::parseBorderImageOutset(RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
6019 return parseBorderImageQuad(FLength | FNumber | FNonNeg, result);
6022 bool CSSPropertyParser::parseBorderRadius(CSSPropertyID propId, bool important)
6024 unsigned num = m_valueList->size();
6028 ShorthandScope scope(this, propId);
6029 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
6031 // Zero initialize the array of raw pointers.
6032 memset(&radii, 0, sizeof(radii));
6035 unsigned indexAfterSlash = 0;
6036 for (unsigned i = 0; i < num; ++i) {
6037 CSSParserValue* value = m_valueList->valueAt(i);
6038 if (value->unit == CSSParserValue::Operator) {
6039 if (value->iValue != '/')
6042 if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
6045 indexAfterSlash = i + 1;
6046 completeBorderRadii(radii[0]);
6050 if (i - indexAfterSlash >= 4)
6053 if (!validUnit(value, FLength | FPercent | FNonNeg))
6056 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
6058 if (!indexAfterSlash) {
6059 radii[0][i] = radius;
6061 // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
6062 if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
6063 indexAfterSlash = 1;
6064 completeBorderRadii(radii[0]);
6067 radii[1][i - indexAfterSlash] = radius.release();
6070 if (!indexAfterSlash) {
6071 completeBorderRadii(radii[0]);
6072 for (unsigned i = 0; i < 4; ++i)
6073 radii[1][i] = radii[0][i];
6075 completeBorderRadii(radii[1]);
6077 ImplicitScope implicitScope(this, PropertyImplicit);
6078 addProperty(CSSPropertyBorderTopLeftRadius, createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()), important);
6079 addProperty(CSSPropertyBorderTopRightRadius, createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()), important);
6080 addProperty(CSSPropertyBorderBottomRightRadius, createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()), important);
6081 addProperty(CSSPropertyBorderBottomLeftRadius, createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()), important);
6085 bool CSSPropertyParser::parseAspectRatio(bool important)
6087 unsigned num = m_valueList->size();
6088 if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
6089 addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(CSSValueNone), important);
6096 CSSParserValue* lvalue = m_valueList->valueAt(0);
6097 CSSParserValue* op = m_valueList->valueAt(1);
6098 CSSParserValue* rvalue = m_valueList->valueAt(2);
6100 if (!isForwardSlashOperator(op))
6103 if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
6106 if (!lvalue->fValue || !rvalue->fValue)
6109 addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important);
6114 bool CSSPropertyParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important)
6116 enum { ID, VAL } state = ID;
6118 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
6119 RefPtrWillBeRawPtr<CSSPrimitiveValue> counterName = nullptr;
6122 CSSParserValue* val = m_valueList->current();
6125 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
6126 counterName = createPrimitiveStringValue(val);
6128 m_valueList->next();
6133 int i = defaultValue;
6134 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
6135 i = clampToInteger(val->fValue);
6136 m_valueList->next();
6139 list->append(createPrimitiveValuePair(counterName.release(),
6140 cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER)));
6148 if (list->length() > 0) {
6149 addProperty(propId, list.release(), important);
6156 // This should go away once we drop support for -webkit-gradient
6157 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
6159 RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
6160 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
6161 if ((equalIgnoringCase(a, "left") && horizontal)
6162 || (equalIgnoringCase(a, "top") && !horizontal))
6163 result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
6164 else if ((equalIgnoringCase(a, "right") && horizontal)
6165 || (equalIgnoringCase(a, "bottom") && !horizontal))
6166 result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
6167 else if (equalIgnoringCase(a, "center"))
6168 result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
6169 } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
6170 result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(a->unit));
6174 bool parseDeprecatedGradientColorStop(CSSPropertyParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
6176 if (a->unit != CSSParserValue::Function)
6179 if (!equalIgnoringCase(a->function->name, "from(") &&
6180 !equalIgnoringCase(a->function->name, "to(") &&
6181 !equalIgnoringCase(a->function->name, "color-stop("))
6184 CSSParserValueList* args = a->function->args.get();
6188 if (equalIgnoringCase(a->function->name, "from(")
6189 || equalIgnoringCase(a->function->name, "to(")) {
6190 // The "from" and "to" stops expect 1 argument.
6191 if (args->size() != 1)
6194 if (equalIgnoringCase(a->function->name, "from("))
6195 stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
6197 stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
6199 CSSValueID id = args->current()->id;
6200 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
6201 stop.m_color = cssValuePool().createIdentifierValue(id);
6203 stop.m_color = p->parseColor(args->current());
6208 // The "color-stop" function expects 3 arguments.
6209 if (equalIgnoringCase(a->function->name, "color-stop(")) {
6210 if (args->size() != 3)
6213 CSSParserValue* stopArg = args->current();
6214 if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
6215 stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
6216 else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
6217 stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
6221 stopArg = args->next();
6222 if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
6225 stopArg = args->next();
6226 CSSValueID id = stopArg->id;
6227 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
6228 stop.m_color = cssValuePool().createIdentifierValue(id);
6230 stop.m_color = p->parseColor(stopArg);
6238 bool CSSPropertyParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient)
6240 // Walk the arguments.
6241 CSSParserValueList* args = valueList->current()->function->args.get();
6242 if (!args || args->size() == 0)
6245 // The first argument is the gradient type. It is an identifier.
6246 CSSGradientType gradientType;
6247 CSSParserValue* a = args->current();
6248 if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
6250 if (equalIgnoringCase(a, "linear"))
6251 gradientType = CSSDeprecatedLinearGradient;
6252 else if (equalIgnoringCase(a, "radial"))
6253 gradientType = CSSDeprecatedRadialGradient;
6257 RefPtrWillBeRawPtr<CSSGradientValue> result = nullptr;
6258 switch (gradientType) {
6259 case CSSDeprecatedLinearGradient:
6260 result = CSSLinearGradientValue::create(NonRepeating, gradientType);
6262 case CSSDeprecatedRadialGradient:
6263 result = CSSRadialGradientValue::create(NonRepeating, gradientType);
6266 // The rest of the gradient types shouldn't appear here.
6267 ASSERT_NOT_REACHED();
6275 // Next comes the starting point for the gradient as an x y pair. There is no
6276 // comma between the x and the y values.
6277 // First X. It can be left, right, number or percent.
6281 RefPtrWillBeRawPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
6284 result->setFirstX(point.release());
6286 // First Y. It can be top, bottom, number or percent.
6290 point = parseDeprecatedGradientPoint(a, false);
6293 result->setFirstY(point.release());
6295 // Comma after the first point.
6300 // For radial gradients only, we now expect a numeric radius.
6301 if (gradientType == CSSDeprecatedRadialGradient) {
6303 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
6305 toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
6307 // Comma after the first radius.
6313 // Next is the ending point for the gradient as an x, y pair.
6314 // Second X. It can be left, right, number or percent.
6318 point = parseDeprecatedGradientPoint(a, true);
6321 result->setSecondX(point.release());
6323 // Second Y. It can be top, bottom, number or percent.
6327 point = parseDeprecatedGradientPoint(a, false);
6330 result->setSecondY(point.release());
6332 // For radial gradients only, we now expect the second radius.
6333 if (gradientType == CSSDeprecatedRadialGradient) {
6334 // Comma after the second point.
6340 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
6342 toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
6345 // We now will accept any number of stops (0 or more).
6348 // Look for the comma before the next stop.
6352 // Now examine the stop itself.
6357 // The function name needs to be one of "from", "to", or "color-stop."
6358 CSSGradientColorStop stop;
6359 if (!parseDeprecatedGradientColorStop(this, a, stop))
6361 result->addStop(stop);
6367 gradient = result.release();
6371 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
6373 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
6379 isHorizontal = true;
6382 case CSSValueBottom:
6383 isHorizontal = false;
6388 return cssValuePool().createIdentifierValue(a->id);
6391 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSPropertyParser* p, CSSParserValue* value)
6393 CSSValueID id = value->id;
6394 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
6395 return cssValuePool().createIdentifierValue(id);
6397 return p->parseColor(value);
6400 bool CSSPropertyParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6402 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient);
6404 // Walk the arguments.
6405 CSSParserValueList* args = valueList->current()->function->args.get();
6406 if (!args || !args->size())
6409 CSSParserValue* a = args->current();
6413 bool expectComma = false;
6415 if (validUnit(a, FAngle, HTMLStandardMode)) {
6416 result->setAngle(createPrimitiveNumericValue(a));
6421 // Look one or two optional keywords that indicate a side or corner.
6422 RefPtrWillBeRawPtr<CSSPrimitiveValue> startX = nullptr;
6423 RefPtrWillBeRawPtr<CSSPrimitiveValue> startY = nullptr;
6425 RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr;
6426 bool isHorizontal = false;
6427 if ((location = valueFromSideKeyword(a, isHorizontal))) {
6433 if ((a = args->next())) {
6434 if ((location = valueFromSideKeyword(a, isHorizontal))) {
6452 if (!startX && !startY)
6453 startY = cssValuePool().createIdentifierValue(CSSValueTop);
6455 result->setFirstX(startX.release());
6456 result->setFirstY(startY.release());
6459 if (!parseGradientColorStops(args, result.get(), expectComma))
6462 if (!result->stopCount())
6465 gradient = result.release();
6469 bool CSSPropertyParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6471 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
6473 // Walk the arguments.
6474 CSSParserValueList* args = valueList->current()->function->args.get();
6475 if (!args || !args->size())
6478 CSSParserValue* a = args->current();
6482 bool expectComma = false;
6484 // Optional background-position
6485 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
6486 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
6487 // parse2ValuesFillPosition advances the args next pointer.
6488 parse2ValuesFillPosition(args, centerX, centerY);
6489 a = args->current();
6493 if (centerX || centerY) {
6503 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
6504 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
6505 // CSS3 radial gradients always share the same start and end point.
6506 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
6507 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
6509 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
6510 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr;
6512 // Optional shape and/or size in any order.
6513 for (int i = 0; i < 2; ++i) {
6514 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
6517 bool foundValue = false;
6519 case CSSValueCircle:
6520 case CSSValueEllipse:
6521 shapeValue = cssValuePool().createIdentifierValue(a->id);
6524 case CSSValueClosestSide:
6525 case CSSValueClosestCorner:
6526 case CSSValueFarthestSide:
6527 case CSSValueFarthestCorner:
6528 case CSSValueContain:
6530 sizeValue = cssValuePool().createIdentifierValue(a->id);
6546 result->setShape(shapeValue);
6547 result->setSizingBehavior(sizeValue);
6549 // Or, two lengths or percentages
6550 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr;
6551 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr;
6553 if (!shapeValue && !sizeValue) {
6554 if (validUnit(a, FLength | FPercent)) {
6555 horizontalSize = createPrimitiveNumericValue(a);
6563 if (validUnit(a, FLength | FPercent)) {
6564 verticalSize = createPrimitiveNumericValue(a);
6573 // Must have neither or both.
6574 if (!horizontalSize != !verticalSize)
6577 result->setEndHorizontalSize(horizontalSize);
6578 result->setEndVerticalSize(verticalSize);
6580 if (!parseGradientColorStops(args, result.get(), expectComma))
6583 gradient = result.release();
6587 bool CSSPropertyParser::parseLinearGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6589 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient);
6591 CSSParserValueList* args = valueList->current()->function->args.get();
6592 if (!args || !args->size())
6595 CSSParserValue* a = args->current();
6599 bool expectComma = false;
6601 if (validUnit(a, FAngle, HTMLStandardMode)) {
6602 result->setAngle(createPrimitiveNumericValue(a));
6606 } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) {
6607 // to [ [left | right] || [top | bottom] ]
6612 RefPtrWillBeRawPtr<CSSPrimitiveValue> endX = nullptr;
6613 RefPtrWillBeRawPtr<CSSPrimitiveValue> endY = nullptr;
6614 RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr;
6615 bool isHorizontal = false;
6617 location = valueFromSideKeyword(a, isHorizontal);
6630 location = valueFromSideKeyword(a, isHorizontal);
6646 result->setFirstX(endX.release());
6647 result->setFirstY(endY.release());
6650 if (!parseGradientColorStops(args, result.get(), expectComma))
6653 if (!result->stopCount())
6656 gradient = result.release();
6660 bool CSSPropertyParser::parseRadialGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6662 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
6664 CSSParserValueList* args = valueList->current()->function->args.get();
6665 if (!args || !args->size())
6668 CSSParserValue* a = args->current();
6672 bool expectComma = false;
6674 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
6675 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr;
6676 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr;
6677 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr;
6679 // First part of grammar, the size/shape clause:
6680 // [ circle || <length> ] |
6681 // [ ellipse || [ <length> | <percentage> ]{2} ] |
6682 // [ [ circle | ellipse] || <size-keyword> ]
6683 for (int i = 0; i < 3; ++i) {
6684 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
6685 bool badIdent = false;
6687 case CSSValueCircle:
6688 case CSSValueEllipse:
6691 shapeValue = cssValuePool().createIdentifierValue(a->id);
6693 case CSSValueClosestSide:
6694 case CSSValueClosestCorner:
6695 case CSSValueFarthestSide:
6696 case CSSValueFarthestCorner:
6697 if (sizeValue || horizontalSize)
6699 sizeValue = cssValuePool().createIdentifierValue(a->id);
6711 } else if (validUnit(a, FLength | FPercent)) {
6713 if (sizeValue || horizontalSize)
6715 horizontalSize = createPrimitiveNumericValue(a);
6721 if (validUnit(a, FLength | FPercent)) {
6722 verticalSize = createPrimitiveNumericValue(a);
6732 // You can specify size as a keyword or a length/percentage, not both.
6733 if (sizeValue && horizontalSize)
6735 // Circles must have 0 or 1 lengths.
6736 if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize)
6738 // Ellipses must have 0 or 2 length/percentages.
6739 if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
6741 // If there's only one size, it must be a length.
6742 if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
6745 result->setShape(shapeValue);
6746 result->setSizingBehavior(sizeValue);
6747 result->setEndHorizontalSize(horizontalSize);
6748 result->setEndVerticalSize(verticalSize);
6750 // Second part of grammar, the center-position clause:
6752 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
6753 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
6754 if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) {
6759 parseFillPosition(args, centerX, centerY);
6760 if (!(centerX && centerY))
6763 a = args->current();
6766 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
6767 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
6768 // Right now, CSS radial gradients have the same start and end centers.
6769 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
6770 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
6773 if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
6776 if (!parseGradientColorStops(args, result.get(), expectComma))
6779 gradient = result.release();
6783 bool CSSPropertyParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
6785 CSSParserValue* a = valueList->current();
6787 // Now look for color stops.
6789 // Look for the comma before the next stop.
6794 a = valueList->next();
6799 // <color-stop> = <color> [ <percentage> | <length> ]?
6800 CSSGradientColorStop stop;
6801 stop.m_color = parseGradientColorOrKeyword(this, a);
6805 a = valueList->next();
6807 if (validUnit(a, FLength | FPercent)) {
6808 stop.m_position = createPrimitiveNumericValue(a);
6809 a = valueList->next();
6813 gradient->addStop(stop);
6817 // Must have 2 or more stops to be valid.
6818 return gradient->stopCount() >= 2;
6821 bool CSSPropertyParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value)
6823 CSSParserValue* val = valueList->current();
6825 if (val->unit != CSSParserValue::Function)
6828 if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) {
6829 // FIXME: This should send a deprecation message.
6830 if (m_context.useCounter())
6831 m_context.useCounter()->count(UseCounter::DeprecatedWebKitGradient);
6832 return parseDeprecatedGradient(valueList, value);
6835 if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")) {
6836 // FIXME: This should send a deprecation message.
6837 if (m_context.useCounter())
6838 m_context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGradient);
6839 return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
6842 if (equalIgnoringCase(val->function->name, "linear-gradient("))
6843 return parseLinearGradient(valueList, value, NonRepeating);
6845 if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")) {
6846 // FIXME: This should send a deprecation message.
6847 if (m_context.useCounter())
6848 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLinearGradient);
6849 return parseDeprecatedLinearGradient(valueList, value, Repeating);
6852 if (equalIgnoringCase(val->function->name, "repeating-linear-gradient("))
6853 return parseLinearGradient(valueList, value, Repeating);
6855 if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")) {
6856 // FIXME: This should send a deprecation message.
6857 if (m_context.useCounter())
6858 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGradient);
6859 return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
6862 if (equalIgnoringCase(val->function->name, "radial-gradient("))
6863 return parseRadialGradient(valueList, value, NonRepeating);
6865 if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")) {
6866 if (m_context.useCounter())
6867 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingRadialGradient);
6868 return parseDeprecatedRadialGradient(valueList, value, Repeating);
6871 if (equalIgnoringCase(val->function->name, "repeating-radial-gradient("))
6872 return parseRadialGradient(valueList, value, Repeating);
6874 if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
6875 return parseCanvas(valueList, value);
6877 if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
6878 return parseCrossfade(valueList, value);
6883 bool CSSPropertyParser::parseCrossfade(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& crossfade)
6885 // Walk the arguments.
6886 CSSParserValueList* args = valueList->current()->function->args.get();
6887 if (!args || args->size() != 5)
6889 CSSParserValue* a = args->current();
6890 RefPtrWillBeRawPtr<CSSValue> fromImageValue = nullptr;
6891 RefPtrWillBeRawPtr<CSSValue> toImageValue = nullptr;
6893 // The first argument is the "from" image. It is a fill image.
6894 if (!a || !parseFillImage(args, fromImageValue))
6903 // The second argument is the "to" image. It is a fill image.
6904 if (!a || !parseFillImage(args, toImageValue))
6913 // The third argument is the crossfade value. It is a percentage or a fractional number.
6914 RefPtrWillBeRawPtr<CSSPrimitiveValue> percentage = nullptr;
6918 if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
6919 percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
6920 else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
6921 percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
6925 RefPtrWillBeRawPtr<CSSCrossfadeValue> result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
6926 result->setPercentage(percentage);
6933 bool CSSPropertyParser::parseCanvas(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& canvas)
6935 // Walk the arguments.
6936 CSSParserValueList* args = valueList->current()->function->args.get();
6937 if (!args || args->size() != 1)
6940 // The first argument is the canvas name. It is an identifier.
6941 CSSParserValue* value = args->current();
6942 if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
6945 canvas = CSSCanvasValue::create(value->string);
6949 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseImageSet(CSSParserValueList* valueList)
6951 CSSParserValue* function = valueList->current();
6953 if (function->unit != CSSParserValue::Function)
6956 CSSParserValueList* functionArgs = valueList->current()->function->args.get();
6957 if (!functionArgs || !functionArgs->size() || !functionArgs->current())
6960 RefPtrWillBeRawPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
6962 CSSParserValue* arg = functionArgs->current();
6964 if (arg->unit != CSSPrimitiveValue::CSS_URI)
6967 RefPtrWillBeRawPtr<CSSImageValue> image = CSSImageValue::create(arg->string, completeURL(arg->string));
6968 imageSet->append(image);
6970 arg = functionArgs->next();
6971 if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
6974 double imageScaleFactor = 0;
6975 const String& string = arg->string;
6976 unsigned length = string.length();
6979 if (string.is8Bit()) {
6980 const LChar* start = string.characters8();
6981 parseDouble(start, start + length, 'x', imageScaleFactor);
6983 const UChar* start = string.characters16();
6984 parseDouble(start, start + length, 'x', imageScaleFactor);
6986 if (imageScaleFactor <= 0)
6988 imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER));
6990 // If there are no more arguments, we're done.
6991 arg = functionArgs->next();
6995 // If there are more arguments, they should be after a comma.
6999 // Skip the comma and move on to the next argument.
7000 arg = functionArgs->next();
7003 return imageSet.release();
7006 bool CSSPropertyParser::parseWillChange(bool important)
7008 ASSERT(RuntimeEnabledFeatures::cssWillChangeEnabled());
7010 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
7011 if (m_valueList->current()->id == CSSValueAuto) {
7012 if (m_valueList->next())
7016 CSSParserValue* currentValue;
7017 bool expectComma = false;
7019 // Every comma-separated list of CSS_IDENTs is a valid will-change value,
7020 // unless the list includes an explicitly disallowed CSS_IDENT.
7021 while ((currentValue = m_valueList->current())) {
7023 if (!isComma(currentValue))
7025 expectComma = false;
7026 m_valueList->next();
7030 if (currentValue->unit != CSSPrimitiveValue::CSS_IDENT)
7033 CSSPropertyID property = cssPropertyID(currentValue->string);
7034 if (property && RuntimeCSSEnabled::isCSSPropertyEnabled(property)) {
7035 if (property == CSSPropertyWillChange)
7037 values->append(cssValuePool().createIdentifierValue(property));
7039 switch (currentValue->id) {
7043 case CSSValueDefault:
7044 case CSSValueInitial:
7045 case CSSValueInherit:
7047 case CSSValueContents:
7048 case CSSValueScrollPosition:
7049 values->append(cssValuePool().createIdentifierValue(currentValue->id));
7056 m_valueList->next();
7059 addProperty(CSSPropertyWillChange, values.release(), important);
7063 bool CSSPropertyParser::isBlendMode(CSSValueID valueID)
7065 return (valueID >= CSSValueMultiply && valueID <= CSSValueLuminosity)
7066 || valueID == CSSValueNormal
7067 || valueID == CSSValueOverlay;
7070 bool CSSPropertyParser::isCompositeOperator(CSSValueID valueID)
7072 // FIXME: Add CSSValueDestination and CSSValueLighter when the Compositing spec updates.
7073 return valueID >= CSSValueClear && valueID <= CSSValueXor;
7076 static void filterInfoForName(const CSSParserString& name, CSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
7078 if (equalIgnoringCase(name, "grayscale("))
7079 filterType = CSSFilterValue::GrayscaleFilterOperation;
7080 else if (equalIgnoringCase(name, "sepia("))
7081 filterType = CSSFilterValue::SepiaFilterOperation;
7082 else if (equalIgnoringCase(name, "saturate("))
7083 filterType = CSSFilterValue::SaturateFilterOperation;
7084 else if (equalIgnoringCase(name, "hue-rotate("))
7085 filterType = CSSFilterValue::HueRotateFilterOperation;
7086 else if (equalIgnoringCase(name, "invert("))
7087 filterType = CSSFilterValue::InvertFilterOperation;
7088 else if (equalIgnoringCase(name, "opacity("))
7089 filterType = CSSFilterValue::OpacityFilterOperation;
7090 else if (equalIgnoringCase(name, "brightness("))
7091 filterType = CSSFilterValue::BrightnessFilterOperation;
7092 else if (equalIgnoringCase(name, "contrast("))
7093 filterType = CSSFilterValue::ContrastFilterOperation;
7094 else if (equalIgnoringCase(name, "blur("))
7095 filterType = CSSFilterValue::BlurFilterOperation;
7096 else if (equalIgnoringCase(name, "drop-shadow(")) {
7097 filterType = CSSFilterValue::DropShadowFilterOperation;
7098 maximumArgumentCount = 4; // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
7102 PassRefPtrWillBeRawPtr<CSSFilterValue> CSSPropertyParser::parseBuiltinFilterArguments(CSSParserValueList* args, CSSFilterValue::FilterOperationType filterType)
7104 RefPtrWillBeRawPtr<CSSFilterValue> filterValue = CSSFilterValue::create(filterType);
7107 switch (filterType) {
7108 case CSSFilterValue::GrayscaleFilterOperation:
7109 case CSSFilterValue::SepiaFilterOperation:
7110 case CSSFilterValue::SaturateFilterOperation:
7111 case CSSFilterValue::InvertFilterOperation:
7112 case CSSFilterValue::OpacityFilterOperation:
7113 case CSSFilterValue::ContrastFilterOperation: {
7114 // One optional argument, 0-1 or 0%-100%, if missing use 100%.
7115 if (args->size() > 1)
7119 CSSParserValue* value = args->current();
7120 if (!validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode))
7123 double amount = value->fValue;
7125 // Saturate and Contrast allow values over 100%.
7126 if (filterType != CSSFilterValue::SaturateFilterOperation
7127 && filterType != CSSFilterValue::ContrastFilterOperation) {
7128 double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
7129 if (amount > maxAllowed)
7133 filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
7137 case CSSFilterValue::BrightnessFilterOperation: {
7138 // One optional argument, if missing use 100%.
7139 if (args->size() > 1)
7143 CSSParserValue* value = args->current();
7144 if (!validUnit(value, FNumber | FPercent, HTMLStandardMode))
7147 filterValue->append(cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
7151 case CSSFilterValue::HueRotateFilterOperation: {
7152 // hue-rotate() takes one optional angle.
7153 if (args->size() > 1)
7157 CSSParserValue* argument = args->current();
7158 if (!validUnit(argument, FAngle, HTMLStandardMode))
7161 filterValue->append(createPrimitiveNumericValue(argument));
7165 case CSSFilterValue::BlurFilterOperation: {
7166 // Blur takes a single length. Zero parameters are allowed.
7167 if (args->size() > 1)
7171 CSSParserValue* argument = args->current();
7172 if (!validUnit(argument, FLength | FNonNeg, HTMLStandardMode))
7175 filterValue->append(createPrimitiveNumericValue(argument));
7179 case CSSFilterValue::DropShadowFilterOperation: {
7180 // drop-shadow() takes a single shadow.
7181 RefPtrWillBeRawPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter);
7182 if (!shadowValueList || shadowValueList->length() != 1)
7185 filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0));
7189 ASSERT_NOT_REACHED();
7191 return filterValue.release();
7194 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFilter()
7199 // The filter is a list of functional primitives that specify individual operations.
7200 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7201 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7202 if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function))
7205 CSSFilterValue::FilterOperationType filterType = CSSFilterValue::UnknownFilterOperation;
7207 // See if the specified primitive is one we understand.
7208 if (value->unit == CSSPrimitiveValue::CSS_URI) {
7209 RefPtrWillBeRawPtr<CSSFilterValue> referenceFilterValue = CSSFilterValue::create(CSSFilterValue::ReferenceFilterOperation);
7210 list->append(referenceFilterValue);
7211 referenceFilterValue->append(CSSSVGDocumentValue::create(value->string));
7213 const CSSParserString name = value->function->name;
7214 unsigned maximumArgumentCount = 1;
7216 filterInfoForName(name, filterType, maximumArgumentCount);
7218 if (filterType == CSSFilterValue::UnknownFilterOperation)
7221 CSSParserValueList* args = value->function->args.get();
7225 RefPtrWillBeRawPtr<CSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType);
7229 list->append(filterValue);
7233 return list.release();
7236 bool CSSPropertyParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtrWillBeRawPtr<CSSValue>& value, RefPtrWillBeRawPtr<CSSValue>& value2, RefPtrWillBeRawPtr<CSSValue>& value3)
7241 if (propId == CSSPropertyWebkitTransformOrigin) {
7242 propId1 = CSSPropertyWebkitTransformOriginX;
7243 propId2 = CSSPropertyWebkitTransformOriginY;
7244 propId3 = CSSPropertyWebkitTransformOriginZ;
7248 case CSSPropertyWebkitTransformOrigin:
7249 if (!parseTransformOriginShorthand(value, value2, value3))
7251 // parseTransformOriginShorthand advances the m_valueList pointer
7253 case CSSPropertyWebkitTransformOriginX: {
7254 value = parseFillPositionX(m_valueList.get());
7256 m_valueList->next();
7259 case CSSPropertyWebkitTransformOriginY: {
7260 value = parseFillPositionY(m_valueList.get());
7262 m_valueList->next();
7265 case CSSPropertyWebkitTransformOriginZ: {
7266 if (validUnit(m_valueList->current(), FLength))
7267 value = createPrimitiveNumericValue(m_valueList->current());
7269 m_valueList->next();
7273 ASSERT_NOT_REACHED();
7280 bool CSSPropertyParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtrWillBeRawPtr<CSSValue>& value, RefPtrWillBeRawPtr<CSSValue>& value2)
7284 if (propId == CSSPropertyWebkitPerspectiveOrigin) {
7285 propId1 = CSSPropertyWebkitPerspectiveOriginX;
7286 propId2 = CSSPropertyWebkitPerspectiveOriginY;
7290 case CSSPropertyWebkitPerspectiveOrigin:
7291 if (m_valueList->size() > 2)
7293 parse2ValuesFillPosition(m_valueList.get(), value, value2);
7295 case CSSPropertyWebkitPerspectiveOriginX: {
7296 value = parseFillPositionX(m_valueList.get());
7298 m_valueList->next();
7301 case CSSPropertyWebkitPerspectiveOriginY: {
7302 value = parseFillPositionY(m_valueList.get());
7304 m_valueList->next();
7308 ASSERT_NOT_REACHED();
7315 bool CSSPropertyParser::parseTouchAction(bool important)
7317 if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
7320 CSSParserValue* value = m_valueList->current();
7321 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7322 if (m_valueList->size() == 1 && value && (value->id == CSSValueAuto || value->id == CSSValueNone || value->id == CSSValueManipulation)) {
7323 list->append(cssValuePool().createIdentifierValue(value->id));
7324 addProperty(CSSPropertyTouchAction, list.release(), important);
7325 m_valueList->next();
7329 bool isValid = true;
7330 while (isValid && value) {
7331 switch (value->id) {
7333 case CSSValuePanY: {
7334 RefPtrWillBeRawPtr<CSSValue> panValue = cssValuePool().createIdentifierValue(value->id);
7335 if (list->hasValue(panValue.get())) {
7339 list->append(panValue.release());
7347 value = m_valueList->next();
7350 if (list->length() && isValid) {
7351 addProperty(CSSPropertyTouchAction, list.release(), important);
7358 void CSSPropertyParser::addTextDecorationProperty(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important)
7360 // The text-decoration-line property takes priority over text-decoration, unless the latter has important priority set.
7361 if (propId == CSSPropertyTextDecoration && !important && !inShorthand()) {
7362 for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
7363 if (m_parsedProperties[i].id() == CSSPropertyTextDecorationLine)
7367 addProperty(propId, value, important);
7370 bool CSSPropertyParser::parseTextDecoration(CSSPropertyID propId, bool important)
7372 if (propId == CSSPropertyTextDecorationLine
7373 && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
7376 CSSParserValue* value = m_valueList->current();
7377 if (value && value->id == CSSValueNone) {
7378 addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
7379 m_valueList->next();
7383 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7384 bool isValid = true;
7385 while (isValid && value) {
7386 switch (value->id) {
7387 case CSSValueUnderline:
7388 case CSSValueOverline:
7389 case CSSValueLineThrough:
7391 list->append(cssValuePool().createIdentifierValue(value->id));
7398 value = m_valueList->next();
7401 // Values are either valid or in shorthand scope.
7402 if (list->length() && (isValid || inShorthand())) {
7403 addTextDecorationProperty(propId, list.release(), important);
7410 bool CSSPropertyParser::parseTextUnderlinePosition(bool important)
7412 // The text-underline-position property has syntax "auto | [ under || [ left | right ] ]".
7413 // However, values 'left' and 'right' are not implemented yet, so we will parse syntax
7414 // "auto | under" for now.
7415 CSSParserValue* value = m_valueList->current();
7416 switch (value->id) {
7419 if (m_valueList->next())
7421 addProperty(CSSPropertyTextUnderlinePosition, cssValuePool().createIdentifierValue(value->id), important);
7428 bool CSSPropertyParser::parseTextEmphasisStyle(bool important)
7430 unsigned valueListSize = m_valueList->size();
7432 RefPtrWillBeRawPtr<CSSPrimitiveValue> fill = nullptr;
7433 RefPtrWillBeRawPtr<CSSPrimitiveValue> shape = nullptr;
7435 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7436 if (value->unit == CSSPrimitiveValue::CSS_STRING) {
7437 if (fill || shape || (valueListSize != 1 && !inShorthand()))
7439 addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important);
7440 m_valueList->next();
7444 if (value->id == CSSValueNone) {
7445 if (fill || shape || (valueListSize != 1 && !inShorthand()))
7447 addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important);
7448 m_valueList->next();
7452 if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
7455 fill = cssValuePool().createIdentifierValue(value->id);
7456 } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
7459 shape = cssValuePool().createIdentifierValue(value->id);
7460 } else if (!inShorthand())
7466 if (fill && shape) {
7467 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
7468 parsedValues->append(fill.release());
7469 parsedValues->append(shape.release());
7470 addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
7474 addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
7478 addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
7485 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTextIndent()
7487 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7489 // <length> | <percentage> | inherit
7490 if (m_valueList->size() == 1) {
7491 CSSParserValue* value = m_valueList->current();
7492 if (!value->id && validUnit(value, FLength | FPercent)) {
7493 list->append(createPrimitiveNumericValue(value));
7494 m_valueList->next();
7495 return list.release();
7499 if (!RuntimeEnabledFeatures::css3TextEnabled())
7502 // The case where text-indent has only <length>(or <percentage>) value
7503 // is handled above if statement even though css3TextEnabled() returns true.
7505 // [ [ <length> | <percentage> ] && each-line ] | inherit
7506 if (m_valueList->size() != 2)
7509 CSSParserValue* firstValue = m_valueList->current();
7510 CSSParserValue* secondValue = m_valueList->next();
7511 CSSParserValue* lengthOrPercentageValue = 0;
7513 // [ <length> | <percentage> ] each-line
7514 if (validUnit(firstValue, FLength | FPercent) && secondValue->id == CSSValueEachLine)
7515 lengthOrPercentageValue = firstValue;
7516 // each-line [ <length> | <percentage> ]
7517 else if (firstValue->id == CSSValueEachLine && validUnit(secondValue, FLength | FPercent))
7518 lengthOrPercentageValue = secondValue;
7520 if (lengthOrPercentageValue) {
7521 list->append(createPrimitiveNumericValue(lengthOrPercentageValue));
7522 list->append(cssValuePool().createIdentifierValue(CSSValueEachLine));
7523 m_valueList->next();
7524 return list.release();
7530 bool CSSPropertyParser::parseLineBoxContain(bool important)
7532 LineBoxContain lineBoxContain = LineBoxContainNone;
7534 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7535 if (value->id == CSSValueBlock) {
7536 if (lineBoxContain & LineBoxContainBlock)
7538 lineBoxContain |= LineBoxContainBlock;
7539 } else if (value->id == CSSValueInline) {
7540 if (lineBoxContain & LineBoxContainInline)
7542 lineBoxContain |= LineBoxContainInline;
7543 } else if (value->id == CSSValueFont) {
7544 if (lineBoxContain & LineBoxContainFont)
7546 lineBoxContain |= LineBoxContainFont;
7547 } else if (value->id == CSSValueGlyphs) {
7548 if (lineBoxContain & LineBoxContainGlyphs)
7550 lineBoxContain |= LineBoxContainGlyphs;
7551 } else if (value->id == CSSValueReplaced) {
7552 if (lineBoxContain & LineBoxContainReplaced)
7554 lineBoxContain |= LineBoxContainReplaced;
7555 } else if (value->id == CSSValueInlineBox) {
7556 if (lineBoxContain & LineBoxContainInlineBox)
7558 lineBoxContain |= LineBoxContainInlineBox;
7563 if (!lineBoxContain)
7566 addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
7570 bool CSSPropertyParser::parseFontFeatureTag(CSSValueList* settings)
7572 // Feature tag name consists of 4-letter characters.
7573 static const unsigned tagNameLength = 4;
7575 CSSParserValue* value = m_valueList->current();
7576 // Feature tag name comes first
7577 if (value->unit != CSSPrimitiveValue::CSS_STRING)
7579 if (value->string.length() != tagNameLength)
7581 for (unsigned i = 0; i < tagNameLength; ++i) {
7582 // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
7583 UChar character = value->string[i];
7584 if (character < 0x20 || character > 0x7E)
7588 AtomicString tag = value->string;
7590 // Feature tag values could follow: <integer> | on | off
7591 value = m_valueList->next();
7593 if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
7594 tagValue = clampToInteger(value->fValue);
7597 m_valueList->next();
7598 } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
7599 tagValue = value->id == CSSValueOn;
7600 m_valueList->next();
7603 settings->append(CSSFontFeatureValue::create(tag, tagValue));
7607 bool CSSPropertyParser::parseFontFeatureSettings(bool important)
7609 if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) {
7610 RefPtrWillBeRawPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal);
7611 m_valueList->next();
7612 addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
7616 RefPtrWillBeRawPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
7617 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7618 if (!parseFontFeatureTag(settings.get()))
7621 // If the list isn't parsed fully, the current value should be comma.
7622 value = m_valueList->current();
7623 if (value && !isComma(value))
7626 if (settings->length()) {
7627 addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important);
7633 bool CSSPropertyParser::parseFontVariantLigatures(bool important)
7635 RefPtrWillBeRawPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
7636 bool sawCommonLigaturesValue = false;
7637 bool sawDiscretionaryLigaturesValue = false;
7638 bool sawHistoricalLigaturesValue = false;
7639 bool sawContextualLigaturesValue = false;
7641 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7642 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
7645 switch (value->id) {
7646 case CSSValueNoCommonLigatures:
7647 case CSSValueCommonLigatures:
7648 if (sawCommonLigaturesValue)
7650 sawCommonLigaturesValue = true;
7651 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
7653 case CSSValueNoDiscretionaryLigatures:
7654 case CSSValueDiscretionaryLigatures:
7655 if (sawDiscretionaryLigaturesValue)
7657 sawDiscretionaryLigaturesValue = true;
7658 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
7660 case CSSValueNoHistoricalLigatures:
7661 case CSSValueHistoricalLigatures:
7662 if (sawHistoricalLigaturesValue)
7664 sawHistoricalLigaturesValue = true;
7665 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
7667 case CSSValueNoContextual:
7668 case CSSValueContextual:
7669 if (sawContextualLigaturesValue)
7671 sawContextualLigaturesValue = true;
7672 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
7679 if (!ligatureValues->length())
7682 addProperty(CSSPropertyFontVariantLigatures, ligatureValues.release(), important);
7686 bool CSSPropertyParser::parseCalculation(CSSParserValue* value, ValueRange range)
7688 ASSERT(isCalculation(value));
7690 CSSParserValueList* args = value->function->args.get();
7691 if (!args || !args->size())
7694 ASSERT(!m_parsedCalculation);
7695 m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
7697 if (!m_parsedCalculation)
7703 bool CSSPropertyParser::parseViewportProperty(CSSPropertyID propId, bool important)
7705 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
7707 CSSParserValue* value = m_valueList->current();
7711 CSSValueID id = value->id;
7712 bool validPrimitive = false;
7715 case CSSPropertyMinWidth: // auto | extend-to-zoom | <length> | <percentage>
7716 case CSSPropertyMaxWidth:
7717 case CSSPropertyMinHeight:
7718 case CSSPropertyMaxHeight:
7719 if (id == CSSValueAuto || id == CSSValueInternalExtendToZoom)
7720 validPrimitive = true;
7722 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
7724 case CSSPropertyWidth: // shorthand
7725 return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMaxWidth, important);
7726 case CSSPropertyHeight:
7727 return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyMaxHeight, important);
7728 case CSSPropertyMinZoom: // auto | <number> | <percentage>
7729 case CSSPropertyMaxZoom:
7730 case CSSPropertyZoom:
7731 if (id == CSSValueAuto)
7732 validPrimitive = true;
7734 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg));
7736 case CSSPropertyUserZoom: // zoom | fixed
7737 if (id == CSSValueZoom || id == CSSValueFixed)
7738 validPrimitive = true;
7740 case CSSPropertyOrientation: // auto | portrait | landscape
7741 if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandscape)
7742 validPrimitive = true;
7747 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
7748 if (validPrimitive) {
7749 parsedValue = parseValidPrimitive(id, value);
7750 m_valueList->next();
7754 if (!m_valueList->current() || inShorthand()) {
7755 addProperty(propId, parsedValue.release(), important);
7763 bool CSSPropertyParser::parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first, CSSPropertyID second, bool important)
7765 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
7766 unsigned numValues = m_valueList->size();
7771 ShorthandScope scope(this, propId);
7773 if (!parseViewportProperty(first, important))
7776 // If just one value is supplied, the second value
7777 // is implicitly initialized with the first value.
7779 m_valueList->previous();
7781 return parseViewportProperty(second, important);
7784 template <typename CharacterType>
7785 static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
7787 char buffer[maxCSSPropertyNameLength + 1]; // 1 for null character
7789 for (unsigned i = 0; i != length; ++i) {
7790 CharacterType c = propertyName[i];
7791 if (c == 0 || c >= 0x7F)
7792 return CSSPropertyInvalid; // illegal character
7793 buffer[i] = toASCIILower(c);
7795 buffer[length] = '\0';
7797 const char* name = buffer;
7798 const Property* hashTableEntry = findProperty(name, length);
7799 return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
7802 CSSPropertyID cssPropertyID(const String& string)
7804 unsigned length = string.length();
7807 return CSSPropertyInvalid;
7808 if (length > maxCSSPropertyNameLength)
7809 return CSSPropertyInvalid;
7811 return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
7814 CSSPropertyID cssPropertyID(const CSSParserString& string)
7816 unsigned length = string.length();
7819 return CSSPropertyInvalid;
7820 if (length > maxCSSPropertyNameLength)
7821 return CSSPropertyInvalid;
7823 return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
7826 template <typename CharacterType>
7827 static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
7829 char buffer[maxCSSValueKeywordLength + 1]; // 1 for null character
7831 for (unsigned i = 0; i != length; ++i) {
7832 CharacterType c = valueKeyword[i];
7833 if (c == 0 || c >= 0x7F)
7834 return CSSValueInvalid; // illegal character
7835 buffer[i] = WTF::toASCIILower(c);
7837 buffer[length] = '\0';
7839 const Value* hashTableEntry = findValue(buffer, length);
7840 return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSValueInvalid;
7843 CSSValueID cssValueKeywordID(const CSSParserString& string)
7845 unsigned length = string.length();
7847 return CSSValueInvalid;
7848 if (length > maxCSSValueKeywordLength)
7849 return CSSValueInvalid;
7851 return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
7854 bool isValidNthToken(const CSSParserString& token)
7856 // The tokenizer checks for the construct of an+b.
7857 // However, since the {ident} rule precedes the {nth} rule, some of those
7858 // tokens are identified as string literal. Furthermore we need to accept
7859 // "odd" and "even" which does not match to an+b.
7860 return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
7861 || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");
7864 bool CSSPropertyParser::isSystemColor(int id)
7866 return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu;
7869 bool CSSPropertyParser::parseSVGValue(CSSPropertyID propId, bool important)
7871 CSSParserValue* value = m_valueList->current();
7875 CSSValueID id = value->id;
7877 bool validPrimitive = false;
7878 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
7881 /* The comment to the right defines all valid value of these
7882 * properties as defined in SVG 1.1, Appendix N. Property index */
7883 case CSSPropertyAlignmentBaseline:
7884 // auto | baseline | before-edge | text-before-edge | middle |
7885 // central | after-edge | text-after-edge | ideographic | alphabetic |
7886 // hanging | mathematical | inherit
7887 if (id == CSSValueAuto || id == CSSValueBaseline || id == CSSValueMiddle
7888 || (id >= CSSValueBeforeEdge && id <= CSSValueMathematical))
7889 validPrimitive = true;
7892 case CSSPropertyBaselineShift:
7893 // baseline | super | sub | <percentage> | <length> | inherit
7894 if (id == CSSValueBaseline || id == CSSValueSub
7895 || id >= CSSValueSuper)
7896 validPrimitive = true;
7898 validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
7901 case CSSPropertyDominantBaseline:
7902 // auto | use-script | no-change | reset-size | ideographic |
7903 // alphabetic | hanging | mathematical | central | middle |
7904 // text-after-edge | text-before-edge | inherit
7905 if (id == CSSValueAuto || id == CSSValueMiddle
7906 || (id >= CSSValueUseScript && id <= CSSValueResetSize)
7907 || (id >= CSSValueCentral && id <= CSSValueMathematical))
7908 validPrimitive = true;
7911 case CSSPropertyEnableBackground:
7912 // accumulate | new [x] [y] [width] [height] | inherit
7913 if (id == CSSValueAccumulate) // TODO : new
7914 validPrimitive = true;
7917 case CSSPropertyMarkerStart:
7918 case CSSPropertyMarkerMid:
7919 case CSSPropertyMarkerEnd:
7920 case CSSPropertyMask:
7921 if (id == CSSValueNone) {
7922 validPrimitive = true;
7923 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
7924 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
7926 m_valueList->next();
7930 case CSSPropertyClipRule: // nonzero | evenodd | inherit
7931 case CSSPropertyFillRule:
7932 if (id == CSSValueNonzero || id == CSSValueEvenodd)
7933 validPrimitive = true;
7936 case CSSPropertyStrokeMiterlimit: // <miterlimit> | inherit
7937 validPrimitive = validUnit(value, FNumber | FNonNeg, SVGAttributeMode);
7940 case CSSPropertyStrokeLinejoin: // miter | round | bevel | inherit
7941 if (id == CSSValueMiter || id == CSSValueRound || id == CSSValueBevel)
7942 validPrimitive = true;
7945 case CSSPropertyStrokeLinecap: // butt | round | square | inherit
7946 if (id == CSSValueButt || id == CSSValueRound || id == CSSValueSquare)
7947 validPrimitive = true;
7950 case CSSPropertyStrokeOpacity: // <opacity-value> | inherit
7951 case CSSPropertyFillOpacity:
7952 case CSSPropertyStopOpacity:
7953 case CSSPropertyFloodOpacity:
7954 validPrimitive = (!id && validUnit(value, FNumber | FPercent, SVGAttributeMode));
7957 case CSSPropertyShapeRendering:
7958 // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
7959 if (id == CSSValueAuto || id == CSSValueOptimizespeed
7960 || id == CSSValueCrispedges || id == CSSValueGeometricprecision)
7961 validPrimitive = true;
7964 case CSSPropertyImageRendering: // auto | optimizeSpeed |
7965 case CSSPropertyColorRendering: // optimizeQuality | inherit
7966 if (id == CSSValueAuto || id == CSSValueOptimizespeed
7967 || id == CSSValueOptimizequality)
7968 validPrimitive = true;
7971 case CSSPropertyBufferedRendering: // auto | dynamic | static
7972 if (id == CSSValueAuto || id == CSSValueDynamic || id == CSSValueStatic)
7973 validPrimitive = true;
7976 case CSSPropertyColorProfile: // auto | sRGB | <name> | <uri> inherit
7977 if (id == CSSValueAuto || id == CSSValueSrgb)
7978 validPrimitive = true;
7981 case CSSPropertyColorInterpolation: // auto | sRGB | linearRGB | inherit
7982 case CSSPropertyColorInterpolationFilters:
7983 if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb)
7984 validPrimitive = true;
7987 /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
7988 * correctly and allows optimization in applyRule(..)
7991 case CSSPropertyTextAnchor: // start | middle | end | inherit
7992 if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd)
7993 validPrimitive = true;
7996 case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit
7997 if (id == CSSValueAuto) {
7998 validPrimitive = true;
8001 /* fallthrough intentional */
8002 case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
8003 if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) {
8004 parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG);
8007 m_valueList->next();
8011 case CSSPropertyFill: // <paint> | inherit
8012 case CSSPropertyStroke: // <paint> | inherit
8014 if (id == CSSValueNone) {
8015 parsedValue = SVGPaint::createNone();
8016 } else if (id == CSSValueCurrentcolor) {
8017 parsedValue = SVGPaint::createCurrentColor();
8018 } else if (isSystemColor(id)) {
8019 parsedValue = SVGPaint::createColor(RenderTheme::theme().systemColor(id));
8020 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
8021 RGBA32 c = Color::transparent;
8022 if (m_valueList->next()) {
8023 if (parseColorFromValue(m_valueList->current(), c))
8024 parsedValue = SVGPaint::createURIAndColor(value->string, c);
8025 else if (m_valueList->current()->id == CSSValueNone)
8026 parsedValue = SVGPaint::createURIAndNone(value->string);
8027 else if (m_valueList->current()->id == CSSValueCurrentcolor)
8028 parsedValue = SVGPaint::createURIAndCurrentColor(value->string);
8031 parsedValue = SVGPaint::createURI(value->string);
8033 parsedValue = parseSVGPaint();
8037 m_valueList->next();
8041 case CSSPropertyStopColor: // TODO : icccolor
8042 case CSSPropertyFloodColor:
8043 case CSSPropertyLightingColor:
8044 if (isSystemColor(id)) {
8045 parsedValue = cssValuePool().createColorValue(RenderTheme::theme().systemColor(id).rgb());
8046 } else if ((id >= CSSValueAqua && id <= CSSValueTransparent)
8047 || (id >= CSSValueAliceblue && id <= CSSValueYellowgreen) || id == CSSValueGrey) {
8048 StyleColor styleColor = SVGPaint::colorFromRGBColorString(value->string);
8049 ASSERT(!styleColor.isCurrentColor());
8050 parsedValue = cssValuePool().createColorValue(styleColor.color().rgb());
8051 } else if (id == CSSValueCurrentcolor) {
8052 parsedValue = cssValuePool().createIdentifierValue(id);
8053 } else { // TODO : svgcolor (iccColor)
8054 parsedValue = parseColor();
8058 m_valueList->next();
8062 case CSSPropertyPaintOrder:
8063 if (!RuntimeEnabledFeatures::svgPaintOrderEnabled())
8066 if (m_valueList->size() == 1 && id == CSSValueNormal)
8067 validPrimitive = true;
8068 else if ((parsedValue = parsePaintOrder()))
8069 m_valueList->next();
8072 case CSSPropertyVectorEffect: // none | non-scaling-stroke | inherit
8073 if (id == CSSValueNone || id == CSSValueNonScalingStroke)
8074 validPrimitive = true;
8077 case CSSPropertyWritingMode:
8078 // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
8079 if (id == CSSValueLrTb || id == CSSValueRlTb || id == CSSValueTbRl || id == CSSValueLr || id == CSSValueRl || id == CSSValueTb)
8080 validPrimitive = true;
8083 case CSSPropertyStrokeWidth: // <length> | inherit
8084 case CSSPropertyStrokeDashoffset:
8085 validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
8087 case CSSPropertyStrokeDasharray: // none | <dasharray> | inherit
8088 if (id == CSSValueNone)
8089 validPrimitive = true;
8091 parsedValue = parseSVGStrokeDasharray();
8095 case CSSPropertyKerning: // auto | normal | <length> | inherit
8096 if (id == CSSValueAuto || id == CSSValueNormal)
8097 validPrimitive = true;
8099 validPrimitive = validUnit(value, FLength, SVGAttributeMode);
8102 case CSSPropertyClipPath: // <uri> | none | inherit
8103 case CSSPropertyFilter:
8104 if (id == CSSValueNone) {
8105 validPrimitive = true;
8106 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
8107 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
8109 m_valueList->next();
8112 case CSSPropertyMaskType: // luminance | alpha | inherit
8113 if (id == CSSValueLuminance || id == CSSValueAlpha)
8114 validPrimitive = true;
8117 /* shorthand properties */
8118 case CSSPropertyMarker: {
8119 ShorthandScope scope(this, propId);
8120 CSSPropertyParser::ImplicitScope implicitScope(this, PropertyImplicit);
8121 if (!parseValue(CSSPropertyMarkerStart, important))
8123 if (m_valueList->current()) {
8124 rollbackLastProperties(1);
8127 CSSValue* value = m_parsedProperties.last().value();
8128 addProperty(CSSPropertyMarkerMid, value, important);
8129 addProperty(CSSPropertyMarkerEnd, value, important);
8133 // If you crash here, it's because you added a css property and are not handling it
8134 // in either this switch statement or the one in CSSPropertyParser::parseValue
8135 ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
8139 if (validPrimitive) {
8141 parsedValue = CSSPrimitiveValue::createIdentifier(id);
8142 else if (value->unit == CSSPrimitiveValue::CSS_STRING)
8143 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
8144 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
8145 parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
8146 else if (value->unit >= CSSParserValue::Q_EMS)
8147 parsedValue = CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
8148 if (isCalculation(value)) {
8149 // FIXME calc() http://webkit.org/b/16662 : actually create a CSSPrimitiveValue here, ie
8150 // parsedValue = CSSPrimitiveValue::create(m_parsedCalculation.release());
8151 m_parsedCalculation.release();
8152 parsedValue = nullptr;
8154 m_valueList->next();
8156 if (!parsedValue || (m_valueList->current() && !inShorthand()))
8159 addProperty(propId, parsedValue.release(), important);
8163 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGStrokeDasharray()
8165 RefPtrWillBeRawPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
8166 CSSParserValue* value = m_valueList->current();
8167 bool validPrimitive = true;
8169 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttributeMode);
8170 if (!validPrimitive)
8173 ret->append(CSSPrimitiveValue::createIdentifier(value->id));
8174 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
8175 ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
8176 value = m_valueList->next();
8177 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
8178 value = m_valueList->next();
8180 if (!validPrimitive)
8182 return ret.release();
8185 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGPaint()
8187 RGBA32 c = Color::transparent;
8188 if (!parseColorFromValue(m_valueList->current(), c))
8189 return SVGPaint::createUnknown();
8190 return SVGPaint::createColor(Color(c));
8193 // normal | [ fill || stroke || markers ]
8194 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parsePaintOrder() const
8196 if (m_valueList->size() > 3)
8199 CSSParserValue* value = m_valueList->current();
8203 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
8205 // The default paint-order is: Fill, Stroke, Markers.
8206 bool seenFill = false, seenStroke = false, seenMarkers = false;
8209 switch (value->id) {
8210 case CSSValueNormal:
8211 // normal inside [fill || stroke || markers] not valid
8219 case CSSValueStroke:
8225 case CSSValueMarkers:
8235 parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id));
8236 } while ((value = m_valueList->next()));
8238 // fill out the rest of the paint order
8240 parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueFill));
8242 parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueStroke));
8244 parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueMarkers));
8246 return parsedValues.release();
8249 } // namespace WebCore