1/*
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.
10 *
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.
15 *
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.
20 *
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.
25 */
26
27#include "config.h"
28#include "core/css/CSSParser.h"
29
30#include "CSSValueKeywords.h"
31#include "RuntimeEnabledFeatures.h"
32#include "StylePropertyShorthand.h"
33#include "core/css/CSSArrayFunctionValue.h"
34#include "core/css/CSSAspectRatioValue.h"
35#include "core/css/CSSBasicShapes.h"
36#include "core/css/CSSBorderImage.h"
37#include "core/css/CSSCanvasValue.h"
38#include "core/css/CSSCrossfadeValue.h"
39#include "core/css/CSSCursorImageValue.h"
40#include "core/css/CSSFontFaceSrcValue.h"
41#include "core/css/CSSFontFeatureValue.h"
42#include "core/css/CSSFunctionValue.h"
43#include "core/css/CSSGradientValue.h"
44#include "core/css/CSSGridLineNamesValue.h"
45#include "core/css/CSSGridTemplateValue.h"
46#include "core/css/CSSImageSetValue.h"
47#include "core/css/CSSImageValue.h"
48#include "core/css/CSSInheritedValue.h"
49#include "core/css/CSSInitialValue.h"
50#include "core/css/CSSKeyframeRule.h"
51#include "core/css/CSSKeyframesRule.h"
52#include "core/css/CSSLineBoxContainValue.h"
53#include "core/css/CSSMixFunctionValue.h"
54#include "core/css/CSSPrimitiveValue.h"
55#include "core/css/CSSPropertySourceData.h"
56#include "core/css/CSSReflectValue.h"
57#include "core/css/CSSSVGDocumentValue.h"
58#include "core/css/CSSSelector.h"
59#include "core/css/CSSShaderValue.h"
60#include "core/css/CSSShadowValue.h"
61#include "core/css/CSSStyleSheet.h"
62#include "core/css/CSSTimingFunctionValue.h"
63#include "core/css/CSSTransformValue.h"
64#include "core/css/CSSUnicodeRangeValue.h"
65#include "core/css/CSSValueList.h"
66#include "core/css/CSSValuePool.h"
67#include "core/css/CSSVariableValue.h"
68#include "core/css/Counter.h"
69#include "core/css/HashTools.h"
70#include "core/css/MediaList.h"
71#include "core/css/MediaQueryExp.h"
72#include "core/css/Pair.h"
73#include "core/css/Rect.h"
74#include "core/css/StylePropertySet.h"
75#include "core/css/StyleRule.h"
76#include "core/css/StyleRuleImport.h"
77#include "core/css/StyleSheetContents.h"
78#include "core/dom/Document.h"
79#include "core/html/parser/HTMLParserIdioms.h"
80#include "core/inspector/InspectorInstrumentation.h"
81#include "core/page/PageConsole.h"
82#include "core/frame/Settings.h"
83#include "core/rendering/RenderTheme.h"
84#include "core/svg/SVGParserUtilities.h"
85#include "platform/FloatConversion.h"
86#include "wtf/BitArray.h"
87#include "wtf/HexNumber.h"
88#include "wtf/text/StringBuffer.h"
89#include "wtf/text/StringBuilder.h"
90#include "wtf/text/StringImpl.h"
91#include "wtf/text/TextEncoding.h"
92#include <limits.h>
93
94#define YYDEBUG 0
95
96#if YYDEBUG > 0
97extern int cssyydebug;
98#endif
99
100extern int cssyyparse(WebCore::CSSParser*);
101
102using namespace std;
103using namespace WTF;
104
105namespace WebCore {
106
107static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
108static const double MAX_SCALE = 1000000;
109
110template <unsigned N>
111static bool equal(const CSSParserString& a, const char (&b)[N])
112{
113    unsigned length = N - 1; // Ignore the trailing null character
114    if (a.length() != length)
115        return false;
116
117    return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar*>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length);
118}
119
120template <unsigned N>
121static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
122{
123    unsigned length = N - 1; // Ignore the trailing null character
124    if (a.length() != length)
125        return false;
126
127    return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length);
128}
129
130template <unsigned N>
131static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N])
132{
133    ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrimitiveValue::CSS_STRING);
134    return equalIgnoringCase(value->string, b);
135}
136
137static PassRefPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtr<CSSPrimitiveValue> first, PassRefPtr<CSSPrimitiveValue> second, Pair::IdenticalValuesPolicy identicalValuesPolicy = Pair::DropIdenticalValues)
138{
139    return cssValuePool().createValue(Pair::create(first, second, identicalValuesPolicy));
140}
141
142class AnimationParseContext {
143public:
144    AnimationParseContext()
145        : m_animationPropertyKeywordAllowed(true)
146        , m_firstAnimationCommitted(false)
147        , m_hasSeenAnimationPropertyKeyword(false)
148    {
149    }
150
151    void commitFirstAnimation()
152    {
153        m_firstAnimationCommitted = true;
154    }
155
156    bool hasCommittedFirstAnimation() const
157    {
158        return m_firstAnimationCommitted;
159    }
160
161    void commitAnimationPropertyKeyword()
162    {
163        m_animationPropertyKeywordAllowed = false;
164    }
165
166    bool animationPropertyKeywordAllowed() const
167    {
168        return m_animationPropertyKeywordAllowed;
169    }
170
171    bool hasSeenAnimationPropertyKeyword() const
172    {
173        return m_hasSeenAnimationPropertyKeyword;
174    }
175
176    void sawAnimationPropertyKeyword()
177    {
178        m_hasSeenAnimationPropertyKeyword = true;
179    }
180
181private:
182    bool m_animationPropertyKeywordAllowed;
183    bool m_firstAnimationCommitted;
184    bool m_hasSeenAnimationPropertyKeyword;
185};
186
187CSSParser::CSSParser(const CSSParserContext& context, UseCounter* counter)
188    : m_context(context)
189    , m_important(false)
190    , m_id(CSSPropertyInvalid)
191    , m_styleSheet(0)
192    , m_supportsCondition(false)
193    , m_selectorListForParseSelector(0)
194    , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
195    , m_inParseShorthand(0)
196    , m_currentShorthand(CSSPropertyInvalid)
197    , m_implicitShorthand(false)
198    , m_hasFontFaceOnlyValues(false)
199    , m_hadSyntacticallyValidCSSRule(false)
200    , m_logErrors(false)
201    , m_ignoreErrors(false)
202    , m_inFilterRule(false)
203    , m_defaultNamespace(starAtom)
204    , m_sourceDataHandler(0)
205    , m_source(0)
206    , m_ruleHeaderType(CSSRuleSourceData::UNKNOWN_RULE)
207    , m_allowImportRules(true)
208    , m_allowNamespaceDeclarations(true)
209    , m_inViewport(false)
210    , m_useCounter(counter)
211    , m_tokenizer(*this)
212{
213#if YYDEBUG > 0
214    cssyydebug = 1;
215#endif
216    CSSPropertySourceData::init();
217}
218
219CSSParser::~CSSParser()
220{
221    clearProperties();
222
223    deleteAllValues(m_floatingSelectors);
224    deleteAllValues(m_floatingSelectorVectors);
225    deleteAllValues(m_floatingValueLists);
226    deleteAllValues(m_floatingFunctions);
227}
228
229void CSSParser::setupParser(const char* prefix, unsigned prefixLength, const String& string, const char* suffix, unsigned suffixLength)
230{
231    m_tokenizer.setupTokenizer(prefix, prefixLength, string, suffix, suffixLength);
232    m_ruleHasHeader = true;
233}
234
235void CSSParser::parseSheet(StyleSheetContents* sheet, const String& string, const TextPosition& startPosition, SourceDataHandler* sourceDataHandler, bool logErrors)
236{
237    setStyleSheet(sheet);
238    m_defaultNamespace = starAtom; // Reset the default namespace.
239    m_sourceDataHandler = sourceDataHandler;
240    m_logErrors = logErrors && sheet->singleOwnerDocument() && !sheet->baseURL().isEmpty() && sheet->singleOwnerDocument()->page();
241    m_ignoreErrors = false;
242    m_tokenizer.m_lineNumber = 0;
243    m_startPosition = startPosition;
244    m_source = &string;
245    m_tokenizer.m_internal = false;
246    setupParser("", string, "");
247    cssyyparse(this);
248    sheet->shrinkToFit();
249    m_source = 0;
250    m_sourceDataHandler = 0;
251    m_rule = 0;
252    m_lineEndings.clear();
253    m_ignoreErrors = false;
254    m_logErrors = false;
255    m_tokenizer.m_internal = true;
256}
257
258PassRefPtr<StyleRuleBase> CSSParser::parseRule(StyleSheetContents* sheet, const String& string)
259{
260    setStyleSheet(sheet);
261    m_allowNamespaceDeclarations = false;
262    setupParser("@-internal-rule ", string, "");
263    cssyyparse(this);
264    return m_rule.release();
265}
266
267PassRefPtr<StyleKeyframe> CSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string)
268{
269    setStyleSheet(sheet);
270    setupParser("@-internal-keyframe-rule ", string, "");
271    cssyyparse(this);
272    return m_keyframe.release();
273}
274
275PassOwnPtr<Vector<double> > CSSParser::parseKeyframeKeyList(const String& string)
276{
277    setupParser("@-internal-keyframe-key-list ", string, "");
278    cssyyparse(this);
279    ASSERT(m_valueList);
280    return StyleKeyframe::createKeyList(m_valueList.get());
281}
282
283bool CSSParser::parseSupportsCondition(const String& string)
284{
285    m_supportsCondition = false;
286    setupParser("@-internal-supports-condition ", string, "");
287    cssyyparse(this);
288    return m_supportsCondition;
289}
290
291static inline bool isColorPropertyID(CSSPropertyID propertyId)
292{
293    switch (propertyId) {
294    case CSSPropertyColor:
295    case CSSPropertyBackgroundColor:
296    case CSSPropertyBorderBottomColor:
297    case CSSPropertyBorderLeftColor:
298    case CSSPropertyBorderRightColor:
299    case CSSPropertyBorderTopColor:
300    case CSSPropertyOutlineColor:
301    case CSSPropertyTextLineThroughColor:
302    case CSSPropertyTextOverlineColor:
303    case CSSPropertyTextUnderlineColor:
304    case CSSPropertyWebkitBorderAfterColor:
305    case CSSPropertyWebkitBorderBeforeColor:
306    case CSSPropertyWebkitBorderEndColor:
307    case CSSPropertyWebkitBorderStartColor:
308    case CSSPropertyWebkitColumnRuleColor:
309    case CSSPropertyWebkitTextEmphasisColor:
310    case CSSPropertyWebkitTextFillColor:
311    case CSSPropertyWebkitTextStrokeColor:
312        return true;
313    case CSSPropertyTextDecorationColor:
314        return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
315    default:
316        return false;
317    }
318}
319
320static bool parseColorValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
321{
322    ASSERT(!string.isEmpty());
323    bool quirksMode = isQuirksModeBehavior(cssParserMode);
324    if (!isColorPropertyID(propertyId))
325        return false;
326    CSSParserString cssString;
327    cssString.init(string);
328    CSSValueID valueID = cssValueKeywordID(cssString);
329    bool validPrimitive = false;
330    if (valueID == CSSValueWebkitText) {
331        validPrimitive = true;
332    } else if (valueID == CSSValueCurrentcolor) {
333        validPrimitive = true;
334    } else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
335        || (quirksMode && valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText)) {
336        validPrimitive = true;
337    }
338
339    if (validPrimitive) {
340        RefPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID);
341        declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
342        return true;
343    }
344    RGBA32 color;
345    if (!CSSParser::fastParseColor(color, string, !quirksMode && string[0] != '#'))
346        return false;
347    RefPtr<CSSValue> value = cssValuePool().createColorValue(color);
348    declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
349    return true;
350}
351
352static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
353{
354    switch (propertyId) {
355    case CSSPropertyFontSize:
356    case CSSPropertyHeight:
357    case CSSPropertyWidth:
358    case CSSPropertyMinHeight:
359    case CSSPropertyMinWidth:
360    case CSSPropertyPaddingBottom:
361    case CSSPropertyPaddingLeft:
362    case CSSPropertyPaddingRight:
363    case CSSPropertyPaddingTop:
364    case CSSPropertyWebkitLogicalWidth:
365    case CSSPropertyWebkitLogicalHeight:
366    case CSSPropertyWebkitMinLogicalWidth:
367    case CSSPropertyWebkitMinLogicalHeight:
368    case CSSPropertyWebkitPaddingAfter:
369    case CSSPropertyWebkitPaddingBefore:
370    case CSSPropertyWebkitPaddingEnd:
371    case CSSPropertyWebkitPaddingStart:
372        acceptsNegativeNumbers = false;
373        return true;
374    case CSSPropertyShapeMargin:
375    case CSSPropertyShapePadding:
376        acceptsNegativeNumbers = false;
377        return RuntimeEnabledFeatures::cssShapesEnabled();
378    case CSSPropertyBottom:
379    case CSSPropertyLeft:
380    case CSSPropertyMarginBottom:
381    case CSSPropertyMarginLeft:
382    case CSSPropertyMarginRight:
383    case CSSPropertyMarginTop:
384    case CSSPropertyRight:
385    case CSSPropertyTop:
386    case CSSPropertyWebkitMarginAfter:
387    case CSSPropertyWebkitMarginBefore:
388    case CSSPropertyWebkitMarginEnd:
389    case CSSPropertyWebkitMarginStart:
390        acceptsNegativeNumbers = true;
391        return true;
392    default:
393        return false;
394    }
395}
396
397template <typename CharacterType>
398static inline bool parseSimpleLength(const CharacterType* characters, unsigned& length, CSSPrimitiveValue::UnitTypes& unit, double& number)
399{
400    if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
401        length -= 2;
402        unit = CSSPrimitiveValue::CSS_PX;
403    } else if (length > 1 && characters[length - 1] == '%') {
404        length -= 1;
405        unit = CSSPrimitiveValue::CSS_PERCENTAGE;
406    }
407
408    // We rely on charactersToDouble for validation as well. The function
409    // will set "ok" to "false" if the entire passed-in character range does
410    // not represent a double.
411    bool ok;
412    number = charactersToDouble(characters, length, &ok);
413    return ok;
414}
415
416static bool parseSimpleLengthValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
417{
418    ASSERT(!string.isEmpty());
419    bool acceptsNegativeNumbers;
420
421    // In @viewport, width and height are shorthands, not simple length values.
422    if (isCSSViewportParsingEnabledForMode(cssParserMode) || !isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
423        return false;
424
425    unsigned length = string.length();
426    double number;
427    CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
428
429    if (string.is8Bit()) {
430        if (!parseSimpleLength(string.characters8(), length, unit, number))
431            return false;
432    } else {
433        if (!parseSimpleLength(string.characters16(), length, unit, number))
434            return false;
435    }
436
437    if (unit == CSSPrimitiveValue::CSS_NUMBER) {
438        bool quirksMode = isQuirksModeBehavior(cssParserMode);
439        if (number && !quirksMode)
440            return false;
441        unit = CSSPrimitiveValue::CSS_PX;
442    }
443    if (number < 0 && !acceptsNegativeNumbers)
444        return false;
445
446    RefPtr<CSSValue> value = cssValuePool().createValue(number, unit);
447    declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
448    return true;
449}
450
451static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext)
452{
453    if (!valueID)
454        return false;
455
456    switch (propertyId) {
457    case CSSPropertyBorderCollapse: // collapse | separate | inherit
458        if (valueID == CSSValueCollapse || valueID == CSSValueSeparate)
459            return true;
460        break;
461    case CSSPropertyBorderTopStyle: // <border-style> | inherit
462    case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
463    case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
464    case CSSPropertyBorderLeftStyle:
465    case CSSPropertyWebkitBorderAfterStyle:
466    case CSSPropertyWebkitBorderBeforeStyle:
467    case CSSPropertyWebkitBorderEndStyle:
468    case CSSPropertyWebkitBorderStartStyle:
469    case CSSPropertyWebkitColumnRuleStyle:
470        if (valueID >= CSSValueNone && valueID <= CSSValueDouble)
471            return true;
472        break;
473    case CSSPropertyBoxSizing:
474         if (valueID == CSSValueBorderBox || valueID == CSSValueContentBox)
475             return true;
476         break;
477    case CSSPropertyCaptionSide: // top | bottom | left | right | inherit
478        if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom)
479            return true;
480        break;
481    case CSSPropertyClear: // none | left | right | both | inherit
482        if (valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth)
483            return true;
484        break;
485    case CSSPropertyDirection: // ltr | rtl | inherit
486        if (valueID == CSSValueLtr || valueID == CSSValueRtl)
487            return true;
488        break;
489    case CSSPropertyDisplay:
490        // inline | block | list-item | inline-block | table |
491        // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
492        // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none | inherit
493        // flex | inline-flex | -webkit-flex | -webkit-inline-flex | grid | inline-grid | lazy-block
494        if ((valueID >= CSSValueInline && valueID <= CSSValueInlineFlex) || valueID == CSSValueWebkitFlex || valueID == CSSValueWebkitInlineFlex || valueID == CSSValueNone)
495            return true;
496        if (valueID == CSSValueGrid || valueID == CSSValueInlineGrid)
497            return RuntimeEnabledFeatures::cssGridLayoutEnabled();
498        break;
499
500    case CSSPropertyEmptyCells: // show | hide | inherit
501        if (valueID == CSSValueShow || valueID == CSSValueHide)
502            return true;
503        break;
504    case CSSPropertyFloat: // left | right | none | center (for buggy CSS, maps to none)
505        if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone || valueID == CSSValueCenter)
506            return true;
507        break;
508    case CSSPropertyFontStyle: // normal | italic | oblique | inherit
509        if (valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique)
510            return true;
511        break;
512    case CSSPropertyImageRendering: // auto | optimizeContrast
513        if (valueID == CSSValueAuto || valueID == CSSValueWebkitOptimizeContrast)
514            return true;
515        break;
516    case CSSPropertyIsolation: // auto | isolate
517        if (valueID == CSSValueAuto || valueID == CSSValueIsolate)
518            return RuntimeEnabledFeatures::cssCompositingEnabled();
519        break;
520    case CSSPropertyListStylePosition: // inside | outside | inherit
521        if (valueID == CSSValueInside || valueID == CSSValueOutside)
522            return true;
523        break;
524    case CSSPropertyListStyleType:
525        // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
526        // for the list of supported list-style-types.
527        if ((valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone)
528            return true;
529        break;
530    case CSSPropertyObjectFit:
531        if (RuntimeEnabledFeatures::objectFitPositionEnabled()) {
532            if (valueID == CSSValueFill || valueID == CSSValueContain || valueID == CSSValueCover || valueID == CSSValueNone || valueID == CSSValueScaleDown)
533                return true;
534        }
535        break;
536    case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit
537        if (valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble))
538            return true;
539        break;
540    case CSSPropertyOverflowWrap: // normal | break-word
541    case CSSPropertyWordWrap:
542        if (valueID == CSSValueNormal || valueID == CSSValueBreakWord)
543            return true;
544        break;
545    case CSSPropertyOverflowX: // visible | hidden | scroll | auto | overlay | inherit
546        if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay)
547            return true;
548        break;
549    case CSSPropertyOverflowY: // visible | hidden | scroll | auto | overlay | inherit | -webkit-paged-x | -webkit-paged-y
550        if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY)
551            return true;
552        break;
553    case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit
554    case CSSPropertyPageBreakBefore:
555    case CSSPropertyWebkitColumnBreakAfter:
556    case CSSPropertyWebkitColumnBreakBefore:
557        if (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight)
558            return true;
559        break;
560    case CSSPropertyPageBreakInside: // avoid | auto | inherit
561    case CSSPropertyWebkitColumnBreakInside:
562        if (valueID == CSSValueAuto || valueID == CSSValueAvoid)
563            return true;
564        break;
565    case CSSPropertyPointerEvents:
566        // none | visiblePainted | visibleFill | visibleStroke | visible |
567        // painted | fill | stroke | auto | all | bounding-box | inherit
568        if (valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueBoundingBox))
569            return true;
570        break;
571    case CSSPropertyPosition: // static | relative | absolute | fixed | sticky | inherit
572        if (valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed
573            || (RuntimeEnabledFeatures::cssStickyPositionEnabled() && valueID == CSSValueSticky))
574            return true;
575        break;
576    case CSSPropertyResize: // none | both | horizontal | vertical | auto
577        if (valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto)
578            return true;
579        break;
580    case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit
581        if (valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation)
582            return true;
583        break;
584    case CSSPropertyTableLayout: // auto | fixed | inherit
585        if (valueID == CSSValueAuto || valueID == CSSValueFixed)
586            return true;
587        break;
588    case CSSPropertyTextAlignLast:
589        // auto | start | end | left | right | center | justify
590        if (RuntimeEnabledFeatures::css3TextEnabled()
591            && ((valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto))
592            return true;
593        break;
594    case CSSPropertyTextJustify:
595        // auto | none | inter-word | distribute
596        if (RuntimeEnabledFeatures::css3TextEnabled()
597            && (valueID == CSSValueInterWord || valueID == CSSValueDistribute || valueID == CSSValueAuto || valueID == CSSValueNone))
598            return true;
599        break;
600    case CSSPropertyTextLineThroughMode:
601    case CSSPropertyTextOverlineMode:
602    case CSSPropertyTextUnderlineMode:
603        if (valueID == CSSValueContinuous || valueID == CSSValueSkipWhiteSpace)
604            return true;
605        break;
606    case CSSPropertyTextLineThroughStyle:
607    case CSSPropertyTextOverlineStyle:
608    case CSSPropertyTextUnderlineStyle:
609        if (valueID == CSSValueNone || valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDashed || valueID == CSSValueDotDash || valueID == CSSValueDotDotDash || valueID == CSSValueWave)
610            return true;
611        break;
612    case CSSPropertyTextOverflow: // clip | ellipsis
613        if (valueID == CSSValueClip || valueID == CSSValueEllipsis)
614            return true;
615        break;
616    case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
617        if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision)
618            return true;
619        break;
620    case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit
621        if ((valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone)
622            return true;
623        break;
624    case CSSPropertyTouchActionDelay: // none | script
625        if (RuntimeEnabledFeatures::cssTouchActionEnabled() && (valueID == CSSValueScript || valueID == CSSValueNone))
626            return true;
627        break;
628    case CSSPropertyVisibility: // visible | hidden | collapse | inherit
629        if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse)
630            return true;
631        break;
632    case CSSPropertyWebkitAppearance:
633        if ((valueID >= CSSValueCheckbox && valueID <= CSSValueTextarea) || valueID == CSSValueNone)
634            return true;
635        break;
636    case CSSPropertyWebkitBackfaceVisibility:
637        if (valueID == CSSValueVisible || valueID == CSSValueHidden)
638            return true;
639        break;
640    case CSSPropertyMixBlendMode:
641        if (RuntimeEnabledFeatures::cssCompositingEnabled() && (valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen
642            || valueID == CSSValueOverlay || valueID == CSSValueDarken || valueID == CSSValueLighten ||  valueID == CSSValueColorDodge
643            || valueID == CSSValueColorBurn || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference
644            || valueID == CSSValueExclusion || valueID == CSSValueHue || valueID == CSSValueSaturation || valueID == CSSValueColor
645            || valueID == CSSValueLuminosity))
646            return true;
647        break;
648    case CSSPropertyWebkitBorderFit:
649        if (valueID == CSSValueBorder || valueID == CSSValueLines)
650            return true;
651        break;
652    case CSSPropertyWebkitBoxAlign:
653        if (valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline)
654            return true;
655        break;
656    case CSSPropertyWebkitBoxDecorationBreak:
657         if (valueID == CSSValueClone || valueID == CSSValueSlice)
658             return true;
659         break;
660    case CSSPropertyWebkitBoxDirection:
661        if (valueID == CSSValueNormal || valueID == CSSValueReverse)
662            return true;
663        break;
664    case CSSPropertyWebkitBoxLines:
665        if (valueID == CSSValueSingle || valueID == CSSValueMultiple)
666                return true;
667        break;
668    case CSSPropertyWebkitBoxOrient:
669        if (valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis)
670            return true;
671        break;
672    case CSSPropertyWebkitBoxPack:
673        if (valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify)
674            return true;
675        break;
676    case CSSPropertyInternalCallback:
677        // This property is only injected programmatically, not parsed from stylesheets.
678        return false;
679    case CSSPropertyColumnFill:
680        if (RuntimeEnabledFeatures::regionBasedColumnsEnabled()) {
681            if (valueID == CSSValueAuto || valueID == CSSValueBalance)
682                return true;
683        }
684        break;
685    case CSSPropertyAlignContent:
686         if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch)
687             return true;
688         break;
689    case CSSPropertyAlignItems:
690        if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
691            return true;
692        break;
693    case CSSPropertyAlignSelf:
694        if (valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
695            return true;
696        break;
697    case CSSPropertyFlexDirection:
698        if (valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse)
699            return true;
700        break;
701    case CSSPropertyFlexWrap:
702        if (valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse)
703             return true;
704        break;
705    case CSSPropertyJustifyContent:
706        if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround)
707            return true;
708        break;
709    case CSSPropertyFontKerning:
710        if (valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone)
711            return true;
712        break;
713    case CSSPropertyWebkitFontSmoothing:
714        if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased)
715            return true;
716        break;
717    case CSSPropertyGridAutoFlow:
718        if (valueID == CSSValueNone || valueID == CSSValueRow || valueID == CSSValueColumn)
719            return RuntimeEnabledFeatures::cssGridLayoutEnabled();
720        break;
721    case CSSPropertyWebkitLineAlign:
722        if (valueID == CSSValueNone || valueID == CSSValueEdges)
723            return true;
724        break;
725    case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
726        if (valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace)
727            return true;
728        break;
729    case CSSPropertyWebkitLineSnap:
730        if (valueID == CSSValueNone || valueID == CSSValueBaseline || valueID == CSSValueContain)
731            return true;
732        break;
733    case CSSPropertyWebkitMarginAfterCollapse:
734    case CSSPropertyWebkitMarginBeforeCollapse:
735    case CSSPropertyWebkitMarginBottomCollapse:
736    case CSSPropertyWebkitMarginTopCollapse:
737        if (valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard)
738            return true;
739        break;
740    case CSSPropertyInternalMarqueeDirection:
741        if (valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
742            || valueID == CSSValueUp || valueID == CSSValueAuto)
743            return true;
744        break;
745    case CSSPropertyInternalMarqueeStyle:
746        if (valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate)
747            return true;
748        break;
749    case CSSPropertyWebkitPrintColorAdjust:
750        if (valueID == CSSValueExact || valueID == CSSValueEconomy)
751            return true;
752        break;
753    case CSSPropertyWebkitRegionBreakAfter:
754    case CSSPropertyWebkitRegionBreakBefore:
755        if (RuntimeEnabledFeatures::cssRegionsEnabled() && (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight))
756            return true;
757        break;
758    case CSSPropertyWebkitRegionBreakInside:
759        if (RuntimeEnabledFeatures::cssRegionsEnabled() && (valueID == CSSValueAuto || valueID == CSSValueAvoid))
760            return true;
761        break;
762    case CSSPropertyWebkitRegionFragment:
763        if (RuntimeEnabledFeatures::cssRegionsEnabled() && (valueID == CSSValueAuto || valueID == CSSValueBreak))
764            return true;
765        break;
766    case CSSPropertyWebkitRtlOrdering:
767        if (valueID == CSSValueLogical || valueID == CSSValueVisual)
768            return true;
769        break;
770
771    case CSSPropertyWebkitRubyPosition:
772        if (valueID == CSSValueBefore || valueID == CSSValueAfter)
773            return true;
774        break;
775
776    case CSSPropertyWebkitTextCombine:
777        if (valueID == CSSValueNone || valueID == CSSValueHorizontal)
778            return true;
779        break;
780    case CSSPropertyWebkitTextEmphasisPosition:
781        if (valueID == CSSValueOver || valueID == CSSValueUnder)
782            return true;
783        break;
784    case CSSPropertyWebkitTextSecurity:
785        // disc | circle | square | none | inherit
786        if (valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone)
787            return true;
788        break;
789    case CSSPropertyWebkitTransformStyle:
790        if (valueID == CSSValueFlat || valueID == CSSValuePreserve3d)
791            return true;
792        break;
793    case CSSPropertyWebkitUserDrag: // auto | none | element
794        if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement)
795            return true;
796        break;
797    case CSSPropertyWebkitUserModify: // read-only | read-write
798        if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly)
799            return true;
800        break;
801    case CSSPropertyWebkitUserSelect: // auto | none | text | all
802        if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll)
803            return true;
804        break;
805    case CSSPropertyWebkitWrapFlow:
806        if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
807            return false;
808        if (valueID == CSSValueAuto || valueID == CSSValueBoth || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueMaximum || valueID == CSSValueClear)
809            return true;
810        break;
811    case CSSPropertyWebkitWrapThrough:
812        if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
813            return false;
814        if (valueID == CSSValueWrap || valueID == CSSValueNone)
815            return true;
816        break;
817    case CSSPropertyWebkitWritingMode:
818        if (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
819            return true;
820        break;
821    case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit
822        if (valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap)
823            return true;
824        break;
825    case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
826        if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord)
827            return true;
828        break;
829    default:
830        ASSERT_NOT_REACHED();
831        return false;
832    }
833    return false;
834}
835
836static inline bool isKeywordPropertyID(CSSPropertyID propertyId)
837{
838    switch (propertyId) {
839    case CSSPropertyMixBlendMode:
840    case CSSPropertyIsolation:
841    case CSSPropertyBorderBottomStyle:
842    case CSSPropertyBorderCollapse:
843    case CSSPropertyBorderLeftStyle:
844    case CSSPropertyBorderRightStyle:
845    case CSSPropertyBorderTopStyle:
846    case CSSPropertyBoxSizing:
847    case CSSPropertyCaptionSide:
848    case CSSPropertyClear:
849    case CSSPropertyDirection:
850    case CSSPropertyDisplay:
851    case CSSPropertyEmptyCells:
852    case CSSPropertyFloat:
853    case CSSPropertyFontStyle:
854    case CSSPropertyImageRendering:
855    case CSSPropertyListStylePosition:
856    case CSSPropertyListStyleType:
857    case CSSPropertyObjectFit:
858    case CSSPropertyOutlineStyle:
859    case CSSPropertyOverflowWrap:
860    case CSSPropertyOverflowX:
861    case CSSPropertyOverflowY:
862    case CSSPropertyPageBreakAfter:
863    case CSSPropertyPageBreakBefore:
864    case CSSPropertyPageBreakInside:
865    case CSSPropertyPointerEvents:
866    case CSSPropertyPosition:
867    case CSSPropertyResize:
868    case CSSPropertySpeak:
869    case CSSPropertyTableLayout:
870    case CSSPropertyTextAlignLast:
871    case CSSPropertyTextJustify:
872    case CSSPropertyTextLineThroughMode:
873    case CSSPropertyTextLineThroughStyle:
874    case CSSPropertyTextOverflow:
875    case CSSPropertyTextOverlineMode:
876    case CSSPropertyTextOverlineStyle:
877    case CSSPropertyTextRendering:
878    case CSSPropertyTextTransform:
879    case CSSPropertyTextUnderlineMode:
880    case CSSPropertyTextUnderlineStyle:
881    case CSSPropertyTouchActionDelay:
882    case CSSPropertyVisibility:
883    case CSSPropertyWebkitAppearance:
884    case CSSPropertyWebkitBackfaceVisibility:
885    case CSSPropertyWebkitBorderAfterStyle:
886    case CSSPropertyWebkitBorderBeforeStyle:
887    case CSSPropertyWebkitBorderEndStyle:
888    case CSSPropertyWebkitBorderFit:
889    case CSSPropertyWebkitBorderStartStyle:
890    case CSSPropertyWebkitBoxAlign:
891    case CSSPropertyWebkitBoxDecorationBreak:
892    case CSSPropertyWebkitBoxDirection:
893    case CSSPropertyWebkitBoxLines:
894    case CSSPropertyWebkitBoxOrient:
895    case CSSPropertyWebkitBoxPack:
896    case CSSPropertyInternalCallback:
897    case CSSPropertyWebkitColumnBreakAfter:
898    case CSSPropertyWebkitColumnBreakBefore:
899    case CSSPropertyWebkitColumnBreakInside:
900    case CSSPropertyColumnFill:
901    case CSSPropertyWebkitColumnRuleStyle:
902    case CSSPropertyAlignContent:
903    case CSSPropertyAlignItems:
904    case CSSPropertyAlignSelf:
905    case CSSPropertyFlexDirection:
906    case CSSPropertyFlexWrap:
907    case CSSPropertyJustifyContent:
908    case CSSPropertyFontKerning:
909    case CSSPropertyWebkitFontSmoothing:
910    case CSSPropertyGridAutoFlow:
911    case CSSPropertyWebkitLineAlign:
912    case CSSPropertyWebkitLineBreak:
913    case CSSPropertyWebkitLineSnap:
914    case CSSPropertyWebkitMarginAfterCollapse:
915    case CSSPropertyWebkitMarginBeforeCollapse:
916    case CSSPropertyWebkitMarginBottomCollapse:
917    case CSSPropertyWebkitMarginTopCollapse:
918    case CSSPropertyInternalMarqueeDirection:
919    case CSSPropertyInternalMarqueeStyle:
920    case CSSPropertyWebkitPrintColorAdjust:
921    case CSSPropertyWebkitRegionBreakAfter:
922    case CSSPropertyWebkitRegionBreakBefore:
923    case CSSPropertyWebkitRegionBreakInside:
924    case CSSPropertyWebkitRegionFragment:
925    case CSSPropertyWebkitRtlOrdering:
926    case CSSPropertyWebkitRubyPosition:
927    case CSSPropertyWebkitTextCombine:
928    case CSSPropertyWebkitTextEmphasisPosition:
929    case CSSPropertyWebkitTextSecurity:
930    case CSSPropertyWebkitTransformStyle:
931    case CSSPropertyWebkitUserDrag:
932    case CSSPropertyWebkitUserModify:
933    case CSSPropertyWebkitUserSelect:
934    case CSSPropertyWebkitWrapFlow:
935    case CSSPropertyWebkitWrapThrough:
936    case CSSPropertyWebkitWritingMode:
937    case CSSPropertyWhiteSpace:
938    case CSSPropertyWordBreak:
939    case CSSPropertyWordWrap:
940        return true;
941    default:
942        return false;
943    }
944}
945
946static bool parseKeywordValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext)
947{
948    ASSERT(!string.isEmpty());
949
950    if (!isKeywordPropertyID(propertyId)) {
951        // All properties accept the values of "initial" and "inherit".
952        String lowerCaseString = string.lower();
953        if (lowerCaseString != "initial" && lowerCaseString != "inherit")
954            return false;
955
956        // Parse initial/inherit shorthands using the CSSParser.
957        if (shorthandForProperty(propertyId).length())
958            return false;
959    }
960
961    CSSParserString cssString;
962    cssString.init(string);
963    CSSValueID valueID = cssValueKeywordID(cssString);
964
965    if (!valueID)
966        return false;
967
968    RefPtr<CSSValue> value;
969    if (valueID == CSSValueInherit)
970        value = cssValuePool().createInheritedValue();
971    else if (valueID == CSSValueInitial)
972        value = cssValuePool().createExplicitInitialValue();
973    else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext))
974        value = cssValuePool().createIdentifierValue(valueID);
975    else
976        return false;
977
978    declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
979    return true;
980}
981
982template <typename CharacterType>
983static bool parseTransformTranslateArguments(CSSTransformValue* transformValue, CharacterType* characters, unsigned length, unsigned start, unsigned expectedCount)
984{
985    while (expectedCount) {
986        size_t end = WTF::find(characters, length, expectedCount == 1 ? ')' : ',', start);
987        if (end == kNotFound || (expectedCount == 1 && end != length - 1))
988            return false;
989        unsigned argumentLength = end - start;
990        CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
991        double number;
992        if (!parseSimpleLength(characters + start, argumentLength, unit, number))
993            return false;
994        if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER))
995            return false;
996        transformValue->append(cssValuePool().createValue(number, CSSPrimitiveValue::CSS_PX));
997        start = end + 1;
998        --expectedCount;
999    }
1000    return true;
1001}
1002
1003static bool parseTranslateTransformValue(MutableStylePropertySet* properties, CSSPropertyID propertyID, const String& string, bool important)
1004{
1005    if (propertyID != CSSPropertyWebkitTransform)
1006        return false;
1007    static const unsigned shortestValidTransformStringLength = 12;
1008    static const unsigned likelyMultipartTransformStringLengthCutoff = 32;
1009    if (string.length() < shortestValidTransformStringLength || string.length() > likelyMultipartTransformStringLengthCutoff)
1010        return false;
1011    if (!string.startsWith("translate", false))
1012        return false;
1013    UChar c9 = toASCIILower(string[9]);
1014    UChar c10 = toASCIILower(string[10]);
1015
1016    CSSTransformValue::TransformOperationType transformType;
1017    unsigned expectedArgumentCount = 1;
1018    unsigned argumentStart = 11;
1019    if (c9 == 'x' && c10 == '(')
1020        transformType = CSSTransformValue::TranslateXTransformOperation;
1021    else if (c9 == 'y' && c10 == '(')
1022        transformType = CSSTransformValue::TranslateYTransformOperation;
1023    else if (c9 == 'z' && c10 == '(')
1024        transformType = CSSTransformValue::TranslateZTransformOperation;
1025    else if (c9 == '(') {
1026        transformType = CSSTransformValue::TranslateTransformOperation;
1027        expectedArgumentCount = 2;
1028        argumentStart = 10;
1029    } else if (c9 == '3' && c10 == 'd' && string[11] == '(') {
1030        transformType = CSSTransformValue::Translate3DTransformOperation;
1031        expectedArgumentCount = 3;
1032        argumentStart = 12;
1033    } else
1034        return false;
1035
1036    RefPtr<CSSTransformValue> transformValue = CSSTransformValue::create(transformType);
1037    bool success;
1038    if (string.is8Bit())
1039        success = parseTransformTranslateArguments(transformValue.get(), string.characters8(), string.length(), argumentStart, expectedArgumentCount);
1040    else
1041        success = parseTransformTranslateArguments(transformValue.get(), string.characters16(), string.length(), argumentStart, expectedArgumentCount);
1042    if (!success)
1043        return false;
1044    RefPtr<CSSValueList> result = CSSValueList::createSpaceSeparated();
1045    result->append(transformValue.release());
1046    properties->addParsedProperty(CSSProperty(CSSPropertyWebkitTransform, result.release(), important));
1047    return true;
1048}
1049
1050PassRefPtr<CSSValueList> CSSParser::parseFontFaceValue(const AtomicString& string)
1051{
1052    if (string.isEmpty())
1053        return 0;
1054    RefPtr<MutableStylePropertySet> dummyStyle = MutableStylePropertySet::create();
1055    if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, HTMLQuirksMode, 0))
1056        return 0;
1057
1058    RefPtr<CSSValue> fontFamily = dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily);
1059    if (!fontFamily->isValueList())
1060        return 0;
1061
1062    return toCSSValueList(dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily).get());
1063}
1064
1065bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, const Document& document)
1066{
1067    ASSERT(!string.isEmpty());
1068
1069    CSSParserContext context(document);
1070
1071    if (parseSimpleLengthValue(declaration, propertyID, string, important, context.mode()))
1072        return true;
1073    if (parseColorValue(declaration, propertyID, string, important, context.mode()))
1074        return true;
1075    if (parseKeywordValue(declaration, propertyID, string, important, context))
1076        return true;
1077
1078    CSSParser parser(context, UseCounter::getFrom(&document));
1079    return parser.parseValue(declaration, propertyID, string, important, static_cast<StyleSheetContents*>(0));
1080}
1081
1082bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
1083{
1084    ASSERT(!string.isEmpty());
1085    if (parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode))
1086        return true;
1087    if (parseColorValue(declaration, propertyID, string, important, cssParserMode))
1088        return true;
1089
1090    CSSParserContext context(cssParserMode);
1091    if (contextStyleSheet) {
1092        context = contextStyleSheet->parserContext();
1093        context.setMode(cssParserMode);
1094    }
1095
1096    if (parseKeywordValue(declaration, propertyID, string, important, context))
1097        return true;
1098    if (parseTranslateTransformValue(declaration, propertyID, string, important))
1099        return true;
1100
1101    CSSParser parser(context);
1102    return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet);
1103}
1104
1105bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet)
1106{
1107    // FIXME: Check RuntimeCSSEnabled::isPropertyEnabled or isValueEnabledForProperty.
1108
1109    if (m_useCounter)
1110        m_useCounter->count(m_context, propertyID);
1111
1112    setStyleSheet(contextStyleSheet);
1113
1114    setupParser("@-internal-value ", string, "");
1115
1116    m_id = propertyID;
1117    m_important = important;
1118
1119    {
1120        StyleDeclarationScope scope(this, declaration);
1121        cssyyparse(this);
1122    }
1123
1124    m_rule = 0;
1125    m_id = CSSPropertyInvalid;
1126
1127    bool ok = false;
1128    if (m_hasFontFaceOnlyValues)
1129        deleteFontFaceOnlyValues();
1130    if (!m_parsedProperties.isEmpty()) {
1131        ok = true;
1132        declaration->addParsedProperties(m_parsedProperties);
1133        clearProperties();
1134    }
1135
1136    return ok;
1137}
1138
1139// The color will only be changed when string contains a valid CSS color, so callers
1140// can set it to a default color and ignore the boolean result.
1141bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
1142{
1143    // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
1144    if (fastParseColor(color, string, strict))
1145        return true;
1146
1147    CSSParser parser(HTMLStandardMode);
1148
1149    // In case the fast-path parser didn't understand the color, try the full parser.
1150    if (!parser.parseColor(string))
1151        return false;
1152
1153    CSSValue* value = parser.m_parsedProperties.first().value();
1154    if (!value->isPrimitiveValue())
1155        return false;
1156
1157    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
1158    if (!primitiveValue->isRGBColor())
1159        return false;
1160
1161    color = primitiveValue->getRGBA32Value();
1162    return true;
1163}
1164
1165bool CSSParser::parseColor(const String& string)
1166{
1167    setupParser("@-internal-decls color:", string, "");
1168    cssyyparse(this);
1169    m_rule = 0;
1170
1171    return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor;
1172}
1173
1174bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document)
1175{
1176    if (!document || !document->page())
1177        return false;
1178
1179    CSSParserString cssColor;
1180    cssColor.init(string);
1181    CSSValueID id = cssValueKeywordID(cssColor);
1182    if (id <= 0)
1183        return false;
1184
1185    color = RenderTheme::theme().systemColor(id).rgb();
1186    return true;
1187}
1188
1189void CSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
1190{
1191    m_selectorListForParseSelector = &selectorList;
1192
1193    setupParser("@-internal-selector ", string, "");
1194
1195    cssyyparse(this);
1196
1197    m_selectorListForParseSelector = 0;
1198}
1199
1200PassRefPtr<ImmutableStylePropertySet> CSSParser::parseInlineStyleDeclaration(const String& string, Element* element)
1201{
1202    Document& document = element->document();
1203    CSSParserContext context = document.elementSheet()->contents()->parserContext();
1204    context.setMode((element->isHTMLElement() && !document.inQuirksMode()) ? HTMLStandardMode : HTMLQuirksMode);
1205    return CSSParser(context, UseCounter::getFrom(&document)).parseDeclaration(string, document.elementSheet()->contents());
1206}
1207
1208PassRefPtr<ImmutableStylePropertySet> CSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet)
1209{
1210    setStyleSheet(contextStyleSheet);
1211
1212    setupParser("@-internal-decls ", string, "");
1213    cssyyparse(this);
1214    m_rule = 0;
1215
1216    if (m_hasFontFaceOnlyValues)
1217        deleteFontFaceOnlyValues();
1218
1219    RefPtr<ImmutableStylePropertySet> style = createStylePropertySet();
1220    clearProperties();
1221    return style.release();
1222}
1223
1224
1225bool CSSParser::parseDeclaration(MutableStylePropertySet* declaration, const String& string, SourceDataHandler* sourceDataHandler, StyleSheetContents* contextStyleSheet)
1226{
1227    setStyleSheet(contextStyleSheet);
1228
1229    m_sourceDataHandler = sourceDataHandler;
1230
1231    setupParser("@-internal-decls ", string, "");
1232    if (m_sourceDataHandler) {
1233        m_sourceDataHandler->startRuleHeader(CSSRuleSourceData::STYLE_RULE, 0);
1234        m_sourceDataHandler->endRuleHeader(1);
1235        m_sourceDataHandler->startRuleBody(0);
1236    }
1237
1238    {
1239        StyleDeclarationScope scope(this, declaration);
1240        cssyyparse(this);
1241    }
1242
1243    m_rule = 0;
1244
1245    bool ok = false;
1246    if (m_hasFontFaceOnlyValues)
1247        deleteFontFaceOnlyValues();
1248    if (!m_parsedProperties.isEmpty()) {
1249        ok = true;
1250        declaration->addParsedProperties(m_parsedProperties);
1251        clearProperties();
1252    }
1253
1254    if (m_sourceDataHandler)
1255        m_sourceDataHandler->endRuleBody(string.length(), false);
1256    m_sourceDataHandler = 0;
1257
1258    return ok;
1259}
1260
1261PassRefPtr<MediaQuerySet> CSSParser::parseMediaQueryList(const String& string)
1262{
1263    ASSERT(!m_mediaList);
1264
1265    // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
1266    // instead insert one " " (which is caught by maybe_space in CSSGrammar.y)
1267    setupParser("@-internal-medialist ", string, "");
1268    cssyyparse(this);
1269
1270    ASSERT(m_mediaList);
1271    return m_mediaList.release();
1272}
1273
1274static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties, HashSet<AtomicString>& seenVariables)
1275{
1276    // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
1277    for (int i = input.size() - 1; i >= 0; --i) {
1278        const CSSProperty& property = input[i];
1279        if (property.isImportant() != important)
1280            continue;
1281        if (property.id() == CSSPropertyVariable) {
1282            const AtomicString& name = toCSSVariableValue(property.value())->name();
1283            if (!seenVariables.add(name).isNewEntry)
1284                continue;
1285            output[--unusedEntries] = property;
1286            continue;
1287        }
1288        const unsigned propertyIDIndex = property.id() - firstCSSProperty;
1289        if (seenProperties.get(propertyIDIndex))
1290            continue;
1291        seenProperties.set(propertyIDIndex);
1292        output[--unusedEntries] = property;
1293    }
1294}
1295
1296PassRefPtr<ImmutableStylePropertySet> CSSParser::createStylePropertySet()
1297{
1298    BitArray<numCSSProperties> seenProperties;
1299    size_t unusedEntries = m_parsedProperties.size();
1300    Vector<CSSProperty, 256> results(unusedEntries);
1301
1302    // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found.
1303    HashSet<AtomicString> seenVariables;
1304    filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
1305    filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
1306    if (unusedEntries)
1307        results.remove(0, unusedEntries);
1308
1309    CSSParserMode mode = inViewport() ? CSSViewportRuleMode : m_context.mode();
1310
1311    return ImmutableStylePropertySet::create(results.data(), results.size(), mode);
1312}
1313
1314void CSSParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
1315{
1316    RefPtr<CSSValue> val = value.get();
1317    addProperty(propId, value, important, implicit);
1318
1319    CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId);
1320    if (prefixingVariant == propId)
1321        return;
1322
1323    if (m_currentShorthand) {
1324        // We can't use ShorthandScope here as we can already be inside one (e.g we are parsing CSSTransition).
1325        m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
1326        addProperty(prefixingVariant, val.release(), important, implicit);
1327        m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
1328    } else {
1329        addProperty(prefixingVariant, val.release(), important, implicit);
1330    }
1331}
1332
1333void CSSParser::addProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
1334{
1335    CSSPrimitiveValue* primitiveValue = value->isPrimitiveValue() ? toCSSPrimitiveValue(value.get()) : 0;
1336    // This property doesn't belong to a shorthand or is a CSS variable (which will be resolved later).
1337    if (!m_currentShorthand || (primitiveValue && primitiveValue->isVariableName())) {
1338        m_parsedProperties.append(CSSProperty(propId, value, important, false, CSSPropertyInvalid, m_implicitShorthand || implicit));
1339        return;
1340    }
1341
1342    Vector<StylePropertyShorthand, 4> shorthands;
1343    getMatchingShorthandsForLonghand(propId, &shorthands);
1344    // The longhand does not belong to multiple shorthands.
1345    if (shorthands.size() == 1)
1346        m_parsedProperties.append(CSSProperty(propId, value, important, true, CSSPropertyInvalid, m_implicitShorthand || implicit));
1347    else
1348        m_parsedProperties.append(CSSProperty(propId, value, important, true, indexOfShorthandForLonghand(m_currentShorthand, shorthands), m_implicitShorthand || implicit));
1349}
1350
1351void CSSParser::rollbackLastProperties(int num)
1352{
1353    ASSERT(num >= 0);
1354    ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
1355    m_parsedProperties.shrink(m_parsedProperties.size() - num);
1356}
1357
1358void CSSParser::clearProperties()
1359{
1360    m_parsedProperties.clear();
1361    m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
1362    m_hasFontFaceOnlyValues = false;
1363}
1364
1365// FIXME: Move to CSSParserContext?
1366KURL CSSParser::completeURL(const CSSParserContext& context, const String& url)
1367{
1368    if (url.isNull())
1369        return KURL();
1370    if (context.charset().isEmpty())
1371        return KURL(context.baseURL(), url);
1372    return KURL(context.baseURL(), url, context.charset());
1373}
1374
1375KURL CSSParser::completeURL(const String& url) const
1376{
1377    return completeURL(m_context, url);
1378}
1379
1380bool CSSParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc)
1381{
1382    bool mustBeNonNegative = unitflags & FNonNeg;
1383
1384    if (!parseCalculation(value, mustBeNonNegative ? ValueRangeNonNegative : ValueRangeAll))
1385        return false;
1386
1387    bool b = false;
1388    switch (m_parsedCalculation->category()) {
1389    case CalcLength:
1390        b = (unitflags & FLength);
1391        break;
1392    case CalcPercent:
1393        b = (unitflags & FPercent);
1394        if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1395            b = false;
1396        break;
1397    case CalcNumber:
1398        b = (unitflags & FNumber);
1399        if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
1400            b = true;
1401        if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1402            b = false;
1403        break;
1404    case CalcPercentLength:
1405        b = (unitflags & FPercent) && (unitflags & FLength);
1406        break;
1407    case CalcPercentNumber:
1408        b = (unitflags & FPercent) && (unitflags & FNumber);
1409        break;
1410    case CalcVariable:
1411        b = true;
1412        break;
1413    case CalcOther:
1414        break;
1415    }
1416    if (!b || releaseCalc == ReleaseParsedCalcValue)
1417        m_parsedCalculation.release();
1418    return b;
1419}
1420
1421inline bool CSSParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
1422{
1423    // Quirks mode and presentation attributes accept unit less values.
1424    return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || isUnitLessLengthParsingEnabledForMode(cssParserMode));
1425}
1426
1427bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
1428{
1429    if (isCalculation(value))
1430        return validCalculationUnit(value, unitflags, releaseCalc);
1431
1432    bool b = false;
1433    switch (value->unit) {
1434    case CSSPrimitiveValue::CSS_VARIABLE_NAME:
1435        // Variables are checked at the point they are dereferenced because unit type is not available here.
1436        b = true;
1437        break;
1438    case CSSPrimitiveValue::CSS_NUMBER:
1439        b = (unitflags & FNumber);
1440        if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
1441            value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
1442                          ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
1443            b = true;
1444        }
1445        if (!b && (unitflags & FInteger) && value->isInt)
1446            b = true;
1447        if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0)
1448            b = true;
1449        break;
1450    case CSSPrimitiveValue::CSS_PERCENTAGE:
1451        b = (unitflags & FPercent);
1452        break;
1453    case CSSParserValue::Q_EMS:
1454    case CSSPrimitiveValue::CSS_EMS:
1455    case CSSPrimitiveValue::CSS_REMS:
1456    case CSSPrimitiveValue::CSS_CHS:
1457    case CSSPrimitiveValue::CSS_EXS:
1458    case CSSPrimitiveValue::CSS_PX:
1459    case CSSPrimitiveValue::CSS_CM:
1460    case CSSPrimitiveValue::CSS_MM:
1461    case CSSPrimitiveValue::CSS_IN:
1462    case CSSPrimitiveValue::CSS_PT:
1463    case CSSPrimitiveValue::CSS_PC:
1464    case CSSPrimitiveValue::CSS_VW:
1465    case CSSPrimitiveValue::CSS_VH:
1466    case CSSPrimitiveValue::CSS_VMIN:
1467    case CSSPrimitiveValue::CSS_VMAX:
1468        b = (unitflags & FLength);
1469        break;
1470    case CSSPrimitiveValue::CSS_MS:
1471    case CSSPrimitiveValue::CSS_S:
1472        b = (unitflags & FTime);
1473        break;
1474    case CSSPrimitiveValue::CSS_DEG:
1475    case CSSPrimitiveValue::CSS_RAD:
1476    case CSSPrimitiveValue::CSS_GRAD:
1477    case CSSPrimitiveValue::CSS_TURN:
1478        b = (unitflags & FAngle);
1479        break;
1480    case CSSPrimitiveValue::CSS_DPPX:
1481    case CSSPrimitiveValue::CSS_DPI:
1482    case CSSPrimitiveValue::CSS_DPCM:
1483        b = (unitflags & FResolution);
1484        break;
1485    case CSSPrimitiveValue::CSS_HZ:
1486    case CSSPrimitiveValue::CSS_KHZ:
1487    case CSSPrimitiveValue::CSS_DIMENSION:
1488    default:
1489        break;
1490    }
1491    if (b && unitflags & FNonNeg && value->fValue < 0)
1492        b = false;
1493    return b;
1494}
1495
1496inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveNumericValue(CSSParserValue* value)
1497{
1498    if (value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
1499        return createPrimitiveVariableNameValue(value);
1500
1501    if (m_parsedCalculation) {
1502        ASSERT(isCalculation(value));
1503        return CSSPrimitiveValue::create(m_parsedCalculation.release());
1504    }
1505
1506    ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1507        || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
1508        || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
1509        || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
1510    return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
1511}
1512
1513inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveStringValue(CSSParserValue* value)
1514{
1515    ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
1516    return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
1517}
1518
1519inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveVariableNameValue(CSSParserValue* value)
1520{
1521    ASSERT(value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME);
1522    return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_VARIABLE_NAME);
1523}
1524
1525static inline bool isComma(CSSParserValue* value)
1526{
1527    return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
1528}
1529
1530static inline bool isForwardSlashOperator(CSSParserValue* value)
1531{
1532    ASSERT(value);
1533    return value->unit == CSSParserValue::Operator && value->iValue == '/';
1534}
1535
1536static bool isGeneratedImageValue(CSSParserValue* val)
1537{
1538    if (val->unit != CSSParserValue::Function)
1539        return false;
1540
1541    return equalIgnoringCase(val->function->name, "-webkit-gradient(")
1542        || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
1543        || equalIgnoringCase(val->function->name, "linear-gradient(")
1544        || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
1545        || equalIgnoringCase(val->function->name, "repeating-linear-gradient(")
1546        || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
1547        || equalIgnoringCase(val->function->name, "radial-gradient(")
1548        || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
1549        || equalIgnoringCase(val->function->name, "repeating-radial-gradient(")
1550        || equalIgnoringCase(val->function->name, "-webkit-canvas(")
1551        || equalIgnoringCase(val->function->name, "-webkit-cross-fade(");
1552}
1553
1554bool CSSParser::validWidthOrHeight(CSSParserValue* value)
1555{
1556    int id = value->id;
1557    if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
1558        return true;
1559    return !id && validUnit(value, FLength | FPercent | FNonNeg);
1560}
1561
1562inline PassRefPtr<CSSPrimitiveValue> CSSParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value)
1563{
1564    if (identifier)
1565        return cssValuePool().createIdentifierValue(identifier);
1566    if (value->unit == CSSPrimitiveValue::CSS_STRING)
1567        return createPrimitiveStringValue(value);
1568    if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1569        return createPrimitiveNumericValue(value);
1570    if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
1571        return createPrimitiveNumericValue(value);
1572    if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
1573        return createPrimitiveNumericValue(value);
1574    if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
1575        return createPrimitiveNumericValue(value);
1576    if (value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
1577        return createPrimitiveVariableNameValue(value);
1578    if (value->unit >= CSSParserValue::Q_EMS)
1579        return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
1580    if (isCalculation(value))
1581        return CSSPrimitiveValue::create(m_parsedCalculation.release());
1582
1583    return 0;
1584}
1585
1586void CSSParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtr<CSSValue> prpValue, bool important)
1587{
1588    const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
1589    unsigned shorthandLength = shorthand.length();
1590    if (!shorthandLength) {
1591        addProperty(propId, prpValue, important);
1592        return;
1593    }
1594
1595    RefPtr<CSSValue> value = prpValue;
1596    ShorthandScope scope(this, propId);
1597    const CSSPropertyID* longhands = shorthand.properties();
1598    for (unsigned i = 0; i < shorthandLength; ++i)
1599        addProperty(longhands[i], value, important);
1600}
1601
1602void CSSParser::setCurrentProperty(CSSPropertyID propId)
1603{
1604    m_id = propId;
1605}
1606
1607bool CSSParser::parseValue(CSSPropertyID propId, bool important)
1608{
1609    if (!isInternalPropertyAndValueParsingEnabledForMode(m_context.mode()) && isInternalProperty(propId))
1610        return false;
1611
1612    // We don't count the UA style sheet in our statistics.
1613    if (m_useCounter)
1614        m_useCounter->count(m_context, propId);
1615
1616    if (!m_valueList)
1617        return false;
1618
1619    CSSParserValue* value = m_valueList->current();
1620
1621    if (!value)
1622        return false;
1623
1624    if (inViewport()) {
1625        // Allow @viewport rules from UA stylesheets even if the feature is disabled.
1626        if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode()))
1627            return false;
1628
1629        return parseViewportProperty(propId, important);
1630    }
1631
1632    // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
1633    // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
1634    ASSERT(!m_parsedCalculation);
1635
1636    CSSValueID id = value->id;
1637
1638    int num = inShorthand() ? 1 : m_valueList->size();
1639
1640    if (id == CSSValueInherit) {
1641        if (num != 1)
1642            return false;
1643        addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important);
1644        return true;
1645    }
1646    else if (id == CSSValueInitial) {
1647        if (num != 1)
1648            return false;
1649        addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important);
1650        return true;
1651    }
1652
1653    if (!id && value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME && num == 1) {
1654        addProperty(propId, createPrimitiveVariableNameValue(value), important);
1655        m_valueList->next();
1656        return true;
1657    }
1658    ASSERT(propId != CSSPropertyVariable);
1659
1660    if (isKeywordPropertyID(propId)) {
1661        if (!isValidKeywordPropertyAndValue(propId, id, m_context))
1662            return false;
1663        if (m_valueList->next() && !inShorthand())
1664            return false;
1665        addProperty(propId, cssValuePool().createIdentifierValue(id), important);
1666        return true;
1667    }
1668
1669    bool validPrimitive = false;
1670    RefPtr<CSSValue> parsedValue;
1671
1672    switch (propId) {
1673    case CSSPropertySize:                 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
1674        return parseSize(propId, important);
1675
1676    case CSSPropertyQuotes:               // [<string> <string>]+ | none | inherit
1677        if (id)
1678            validPrimitive = true;
1679        else
1680            return parseQuotes(propId, important);
1681        break;
1682    case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | isolate-override | plaintext | inherit
1683        if (id == CSSValueNormal
1684            || id == CSSValueEmbed
1685            || id == CSSValueBidiOverride
1686            || id == CSSValueWebkitIsolate
1687            || id == CSSValueWebkitIsolateOverride
1688            || id == CSSValueWebkitPlaintext)
1689            validPrimitive = true;
1690        break;
1691
1692    case CSSPropertyContent:              // [ <string> | <uri> | <counter> | attr(X) | open-quote |
1693        // close-quote | no-open-quote | no-close-quote ]+ | inherit
1694        return parseContent(propId, important);
1695
1696    case CSSPropertyClip:                 // <shape> | auto | inherit
1697        if (id == CSSValueAuto)
1698            validPrimitive = true;
1699        else if (value->unit == CSSParserValue::Function)
1700            return parseClipShape(propId, important);
1701        break;
1702
1703    /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
1704     * correctly and allows optimization in WebCore::applyRule(..)
1705     */
1706    case CSSPropertyOverflow: {
1707        ShorthandScope scope(this, propId);
1708        if (num != 1 || !parseValue(CSSPropertyOverflowY, important))
1709            return false;
1710
1711        RefPtr<CSSValue> overflowXValue;
1712
1713        // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been
1714        // set using the shorthand, then for now overflow-x will default to auto, but once we implement
1715        // pagination controls, it should default to hidden. If the overflow-y value is anything but
1716        // paged-x or paged-y, then overflow-x and overflow-y should have the same value.
1717        if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
1718            overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
1719        else
1720            overflowXValue = m_parsedProperties.last().value();
1721        addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
1722        return true;
1723    }
1724
1725    case CSSPropertyTextAlign:
1726        // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
1727        // | start | end | <string> | inherit | -webkit-auto (converted to start)
1728        if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
1729            || value->unit == CSSPrimitiveValue::CSS_STRING)
1730            validPrimitive = true;
1731        break;
1732
1733    case CSSPropertyFontWeight:  { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
1734        if (m_valueList->size() != 1)
1735            return false;
1736        return parseFontWeight(important);
1737    }
1738    case CSSPropertyBorderSpacing: {
1739        if (num == 1) {
1740            ShorthandScope scope(this, CSSPropertyBorderSpacing);
1741            if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
1742                return false;
1743            CSSValue* value = m_parsedProperties.last().value();
1744            addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
1745            return true;
1746        }
1747        else if (num == 2) {
1748            ShorthandScope scope(this, CSSPropertyBorderSpacing);
1749            if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
1750                return false;
1751            return true;
1752        }
1753        return false;
1754    }
1755    case CSSPropertyWebkitBorderHorizontalSpacing:
1756    case CSSPropertyWebkitBorderVerticalSpacing:
1757        validPrimitive = validUnit(value, FLength | FNonNeg);
1758        break;
1759    case CSSPropertyOutlineColor:        // <color> | invert | inherit
1760        // Outline color has "invert" as additional keyword.
1761        // Also, we want to allow the special focus color even in HTML Standard parsing mode.
1762        if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
1763            validPrimitive = true;
1764            break;
1765        }
1766        /* nobreak */
1767    case CSSPropertyBackgroundColor: // <color> | inherit
1768    case CSSPropertyBorderTopColor: // <color> | inherit
1769    case CSSPropertyBorderRightColor:
1770    case CSSPropertyBorderBottomColor:
1771    case CSSPropertyBorderLeftColor:
1772    case CSSPropertyWebkitBorderStartColor:
1773    case CSSPropertyWebkitBorderEndColor:
1774    case CSSPropertyWebkitBorderBeforeColor:
1775    case CSSPropertyWebkitBorderAfterColor:
1776    case CSSPropertyColor: // <color> | inherit
1777    case CSSPropertyTextDecorationColor: // CSS3 text decoration colors
1778    case CSSPropertyTextLineThroughColor:
1779    case CSSPropertyTextUnderlineColor:
1780    case CSSPropertyTextOverlineColor:
1781    case CSSPropertyWebkitColumnRuleColor:
1782    case CSSPropertyWebkitTextEmphasisColor:
1783    case CSSPropertyWebkitTextFillColor:
1784    case CSSPropertyWebkitTextStrokeColor:
1785        if (propId == CSSPropertyTextDecorationColor
1786            && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
1787            return false;
1788
1789        if ((id >= CSSValueAqua && id <= CSSValueWebkitText) || id == CSSValueMenu) {
1790            validPrimitive = isValueAllowedInMode(id, m_context.mode());
1791        } else {
1792            parsedValue = parseColor();
1793            if (parsedValue)
1794                m_valueList->next();
1795        }
1796        break;
1797
1798    case CSSPropertyCursor: {
1799        // Grammar defined by CSS3 UI and modified by CSS4 images:
1800        // [ [<image> [<x> <y>]?,]*
1801        // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
1802        // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
1803        // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
1804        // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
1805        // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
1806        RefPtr<CSSValueList> list;
1807        while (value) {
1808            RefPtr<CSSValue> image = 0;
1809            if (value->unit == CSSPrimitiveValue::CSS_URI) {
1810                String uri = value->string;
1811                if (!uri.isNull())
1812                    image = CSSImageValue::create(completeURL(uri));
1813            } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
1814                image = parseImageSet(m_valueList.get());
1815                if (!image)
1816                    break;
1817            } else
1818                break;
1819
1820            Vector<int> coords;
1821            value = m_valueList->next();
1822            while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
1823                coords.append(int(value->fValue));
1824                value = m_valueList->next();
1825            }
1826            bool hasHotSpot = false;
1827            IntPoint hotSpot(-1, -1);
1828            int nrcoords = coords.size();
1829            if (nrcoords > 0 && nrcoords != 2)
1830                return false;
1831            if (nrcoords == 2) {
1832                hasHotSpot = true;
1833                hotSpot = IntPoint(coords[0], coords[1]);
1834            }
1835
1836            if (!list)
1837                list = CSSValueList::createCommaSeparated();
1838
1839            if (image)
1840                list->append(CSSCursorImageValue::create(image, hasHotSpot, hotSpot));
1841
1842            if (!value || !(value->unit == CSSParserValue::Operator && value->iValue == ','))
1843                return false;
1844            value = m_valueList->next(); // comma
1845        }
1846        if (list) {
1847            if (!value)
1848                return false;
1849            if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
1850                list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
1851            else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
1852                list->append(cssValuePool().createIdentifierValue(value->id));
1853            m_valueList->next();
1854            parsedValue = list.release();
1855            break;
1856        } else if (value) {
1857            id = value->id;
1858            if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
1859                id = CSSValuePointer;
1860                validPrimitive = true;
1861            } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
1862                validPrimitive = true;
1863        } else {
1864            ASSERT_NOT_REACHED();
1865            return false;
1866        }
1867        break;
1868    }
1869
1870    case CSSPropertyBackgroundBlendMode:
1871    case CSSPropertyBackgroundAttachment:
1872    case CSSPropertyBackgroundClip:
1873    case CSSPropertyWebkitBackgroundClip:
1874    case CSSPropertyWebkitBackgroundComposite:
1875    case CSSPropertyBackgroundImage:
1876    case CSSPropertyBackgroundOrigin:
1877    case CSSPropertyMaskSourceType:
1878    case CSSPropertyWebkitBackgroundOrigin:
1879    case CSSPropertyBackgroundPosition:
1880    case CSSPropertyBackgroundPositionX:
1881    case CSSPropertyBackgroundPositionY:
1882    case CSSPropertyBackgroundSize:
1883    case CSSPropertyWebkitBackgroundSize:
1884    case CSSPropertyBackgroundRepeat:
1885    case CSSPropertyBackgroundRepeatX:
1886    case CSSPropertyBackgroundRepeatY:
1887    case CSSPropertyWebkitMaskClip:
1888    case CSSPropertyWebkitMaskComposite:
1889    case CSSPropertyWebkitMaskImage:
1890    case CSSPropertyWebkitMaskOrigin:
1891    case CSSPropertyWebkitMaskPosition:
1892    case CSSPropertyWebkitMaskPositionX:
1893    case CSSPropertyWebkitMaskPositionY:
1894    case CSSPropertyWebkitMaskSize:
1895    case CSSPropertyWebkitMaskRepeat:
1896    case CSSPropertyWebkitMaskRepeatX:
1897    case CSSPropertyWebkitMaskRepeatY:
1898    {
1899        RefPtr<CSSValue> val1;
1900        RefPtr<CSSValue> val2;
1901        CSSPropertyID propId1, propId2;
1902        bool result = false;
1903        if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
1904            OwnPtr<ShorthandScope> shorthandScope;
1905            if (propId == CSSPropertyBackgroundPosition ||
1906                propId == CSSPropertyBackgroundRepeat ||
1907                propId == CSSPropertyWebkitMaskPosition ||
1908                propId == CSSPropertyWebkitMaskRepeat) {
1909                shorthandScope = adoptPtr(new ShorthandScope(this, propId));
1910            }
1911            addProperty(propId1, val1.release(), important);
1912            if (val2)
1913                addProperty(propId2, val2.release(), important);
1914            result = true;
1915        }
1916        m_implicitShorthand = false;
1917        return result;
1918    }
1919    case CSSPropertyObjectPosition:
1920        return RuntimeEnabledFeatures::objectFitPositionEnabled() && parseObjectPosition(important);
1921    case CSSPropertyListStyleImage:     // <uri> | none | inherit
1922    case CSSPropertyBorderImageSource:
1923    case CSSPropertyWebkitMaskBoxImageSource:
1924        if (id == CSSValueNone) {
1925            parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
1926            m_valueList->next();
1927        } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
1928            parsedValue = CSSImageValue::create(completeURL(value->string));
1929            m_valueList->next();
1930        } else if (isGeneratedImageValue(value)) {
1931            if (parseGeneratedImage(m_valueList.get(), parsedValue))
1932                m_valueList->next();
1933            else
1934                return false;
1935        }
1936        else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
1937            parsedValue = parseImageSet(m_valueList.get());
1938            if (!parsedValue)
1939                return false;
1940            m_valueList->next();
1941        }
1942        break;
1943
1944    case CSSPropertyWebkitTextStrokeWidth:
1945    case CSSPropertyOutlineWidth:        // <border-width> | inherit
1946    case CSSPropertyBorderTopWidth:     //// <border-width> | inherit
1947    case CSSPropertyBorderRightWidth:   //   Which is defined as
1948    case CSSPropertyBorderBottomWidth:  //   thin | medium | thick | <length>
1949    case CSSPropertyBorderLeftWidth:
1950    case CSSPropertyWebkitBorderStartWidth:
1951    case CSSPropertyWebkitBorderEndWidth:
1952    case CSSPropertyWebkitBorderBeforeWidth:
1953    case CSSPropertyWebkitBorderAfterWidth:
1954    case CSSPropertyWebkitColumnRuleWidth:
1955        if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
1956            validPrimitive = true;
1957        else
1958            validPrimitive = validUnit(value, FLength | FNonNeg);
1959        break;
1960
1961    case CSSPropertyLetterSpacing:       // normal | <length> | inherit
1962    case CSSPropertyWordSpacing:         // normal | <length> | inherit
1963        if (id == CSSValueNormal)
1964            validPrimitive = true;
1965        else
1966            validPrimitive = validUnit(value, FLength);
1967        break;
1968
1969    case CSSPropertyTextIndent:
1970        parsedValue = parseTextIndent();
1971        break;
1972
1973    case CSSPropertyPaddingTop:          //// <padding-width> | inherit
1974    case CSSPropertyPaddingRight:        //   Which is defined as
1975    case CSSPropertyPaddingBottom:       //   <length> | <percentage>
1976    case CSSPropertyPaddingLeft:         ////
1977    case CSSPropertyWebkitPaddingStart:
1978    case CSSPropertyWebkitPaddingEnd:
1979    case CSSPropertyWebkitPaddingBefore:
1980    case CSSPropertyWebkitPaddingAfter:
1981        validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
1982        break;
1983
1984    case CSSPropertyMaxWidth:
1985    case CSSPropertyWebkitMaxLogicalWidth:
1986    case CSSPropertyMaxHeight:
1987    case CSSPropertyWebkitMaxLogicalHeight:
1988        validPrimitive = (id == CSSValueNone || validWidthOrHeight(value));
1989        break;
1990
1991    case CSSPropertyMinWidth:
1992    case CSSPropertyWebkitMinLogicalWidth:
1993    case CSSPropertyMinHeight:
1994    case CSSPropertyWebkitMinLogicalHeight:
1995        validPrimitive = validWidthOrHeight(value);
1996        break;
1997
1998    case CSSPropertyWidth:
1999    case CSSPropertyWebkitLogicalWidth:
2000    case CSSPropertyHeight:
2001    case CSSPropertyWebkitLogicalHeight:
2002        validPrimitive = (id == CSSValueAuto || validWidthOrHeight(value));
2003        break;
2004
2005    case CSSPropertyFontSize:
2006        return parseFontSize(important);
2007
2008    case CSSPropertyFontVariant:         // normal | small-caps | inherit
2009        return parseFontVariant(important);
2010
2011    case CSSPropertyVerticalAlign:
2012        // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
2013        // <percentage> | <length> | inherit
2014
2015        if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
2016            validPrimitive = true;
2017        else
2018            validPrimitive = (!id && validUnit(value, FLength | FPercent));
2019        break;
2020
2021    case CSSPropertyBottom:               // <length> | <percentage> | auto | inherit
2022    case CSSPropertyLeft:                 // <length> | <percentage> | auto | inherit
2023    case CSSPropertyRight:                // <length> | <percentage> | auto | inherit
2024    case CSSPropertyTop:                  // <length> | <percentage> | auto | inherit
2025    case CSSPropertyMarginTop:           //// <margin-width> | inherit
2026    case CSSPropertyMarginRight:         //   Which is defined as
2027    case CSSPropertyMarginBottom:        //   <length> | <percentage> | auto | inherit
2028    case CSSPropertyMarginLeft:          ////
2029    case CSSPropertyWebkitMarginStart:
2030    case CSSPropertyWebkitMarginEnd:
2031    case CSSPropertyWebkitMarginBefore:
2032    case CSSPropertyWebkitMarginAfter:
2033        if (id == CSSValueAuto)
2034            validPrimitive = true;
2035        else
2036            validPrimitive = (!id && validUnit(value, FLength | FPercent));
2037        break;
2038
2039    case CSSPropertyZIndex:              // auto | <integer> | inherit
2040        if (id == CSSValueAuto) {
2041            validPrimitive = true;
2042            break;
2043        }
2044        /* nobreak */
2045    case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
2046    case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
2047        if (id == CSSValueAuto)
2048            validPrimitive = true;
2049        else
2050            validPrimitive = (!id && validUnit(value, FInteger, HTMLQuirksMode));
2051        break;
2052
2053    case CSSPropertyLineHeight:
2054        return parseLineHeight(important);
2055    case CSSPropertyCounterIncrement:    // [ <identifier> <integer>? ]+ | none | inherit
2056        if (id != CSSValueNone)
2057            return parseCounter(propId, 1, important);
2058        validPrimitive = true;
2059        break;
2060    case CSSPropertyCounterReset:        // [ <identifier> <integer>? ]+ | none | inherit
2061        if (id != CSSValueNone)
2062            return parseCounter(propId, 0, important);
2063        validPrimitive = true;
2064        break;
2065    case CSSPropertyFontFamily:
2066        // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
2067    {
2068        parsedValue = parseFontFamily();
2069        break;
2070    }
2071
2072    case CSSPropertyTextDecoration:
2073        // Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration
2074        // is disabled to match CSS 2.1 rules for parsing 'text-decoration'.
2075        if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) {
2076            // [ <text-decoration-line> || <text-decoration-style> || <text-decoration-color> ] | inherit
2077            return parseShorthand(CSSPropertyTextDecoration, textDecorationShorthand(), important);
2078        }
2079    case CSSPropertyWebkitTextDecorationsInEffect:
2080    case CSSPropertyTextDecorationLine:
2081        // none | [ underline || overline || line-through || blink ] | inherit
2082        return parseTextDecoration(propId, important);
2083
2084    case CSSPropertyTextDecorationStyle:
2085        // solid | double | dotted | dashed | wavy
2086        if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()
2087            && (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDotted || id == CSSValueDashed || id == CSSValueWavy))
2088            validPrimitive = true;
2089        break;
2090
2091    case CSSPropertyTextUnderlinePosition:
2092        // auto | under | inherit
2093        if (RuntimeEnabledFeatures::css3TextDecorationsEnabled())
2094            return parseTextUnderlinePosition(important);
2095        return false;
2096
2097    case CSSPropertyZoom:          // normal | reset | document | <number> | <percentage> | inherit
2098        if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
2099            validPrimitive = true;
2100        else
2101            validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode));
2102        break;
2103
2104    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.
2105        if (m_inFilterRule)
2106            return parseFilterRuleSrc();
2107        return parseFontFaceSrc();
2108
2109    case CSSPropertyUnicodeRange:
2110        return parseFontFaceUnicodeRange();
2111
2112    /* CSS3 properties */
2113
2114    case CSSPropertyBorderImage:
2115    case CSSPropertyWebkitMaskBoxImage:
2116        return parseBorderImageShorthand(propId, important);
2117    case CSSPropertyWebkitBorderImage: {
2118        if (RefPtr<CSSValue> result = parseBorderImage(propId)) {
2119            addProperty(propId, result, important);
2120            return true;
2121        }
2122        return false;
2123    }
2124
2125    case CSSPropertyBorderImageOutset:
2126    case CSSPropertyWebkitMaskBoxImageOutset: {
2127        RefPtr<CSSPrimitiveValue> result;
2128        if (parseBorderImageOutset(result)) {
2129            addProperty(propId, result, important);
2130            return true;
2131        }
2132        break;
2133    }
2134    case CSSPropertyBorderImageRepeat:
2135    case CSSPropertyWebkitMaskBoxImageRepeat: {
2136        RefPtr<CSSValue> result;
2137        if (parseBorderImageRepeat(result)) {
2138            addProperty(propId, result, important);
2139            return true;
2140        }
2141        break;
2142    }
2143    case CSSPropertyBorderImageSlice:
2144    case CSSPropertyWebkitMaskBoxImageSlice: {
2145        RefPtr<CSSBorderImageSliceValue> result;
2146        if (parseBorderImageSlice(propId, result)) {
2147            addProperty(propId, result, important);
2148            return true;
2149        }
2150        break;
2151    }
2152    case CSSPropertyBorderImageWidth:
2153    case CSSPropertyWebkitMaskBoxImageWidth: {
2154        RefPtr<CSSPrimitiveValue> result;
2155        if (parseBorderImageWidth(result)) {
2156            addProperty(propId, result, important);
2157            return true;
2158        }
2159        break;
2160    }
2161    case CSSPropertyBorderTopRightRadius:
2162    case CSSPropertyBorderTopLeftRadius:
2163    case CSSPropertyBorderBottomLeftRadius:
2164    case CSSPropertyBorderBottomRightRadius: {
2165        if (num != 1 && num != 2)
2166            return false;
2167        validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2168        if (!validPrimitive)
2169            return false;
2170        RefPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
2171        RefPtr<CSSPrimitiveValue> parsedValue2;
2172        if (num == 2) {
2173            value = m_valueList->next();
2174            validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2175            if (!validPrimitive)
2176                return false;
2177            parsedValue2 = createPrimitiveNumericValue(value);
2178        } else
2179            parsedValue2 = parsedValue1;
2180
2181        addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important);
2182        return true;
2183    }
2184    case CSSPropertyTabSize:
2185        validPrimitive = validUnit(value, FInteger | FNonNeg);
2186        break;
2187    case CSSPropertyWebkitAspectRatio:
2188        return parseAspectRatio(important);
2189    case CSSPropertyBorderRadius:
2190    case CSSPropertyWebkitBorderRadius:
2191        return parseBorderRadius(propId, important);
2192    case CSSPropertyOutlineOffset:
2193        validPrimitive = validUnit(value, FLength);
2194        break;
2195    case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
2196    case CSSPropertyBoxShadow:
2197    case CSSPropertyWebkitBoxShadow:
2198        if (id == CSSValueNone)
2199            validPrimitive = true;
2200        else {
2201            RefPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
2202            if (shadowValueList) {
2203                addProperty(propId, shadowValueList.release(), important);
2204                m_valueList->next();
2205                return true;
2206            }
2207            return false;
2208        }
2209        break;
2210    case CSSPropertyWebkitBoxReflect:
2211        if (id == CSSValueNone)
2212            validPrimitive = true;
2213        else
2214            return parseReflect(propId, important);
2215        break;
2216    case CSSPropertyOpacity:
2217        validPrimitive = validUnit(value, FNumber);
2218        break;
2219    case CSSPropertyWebkitBoxFlex:
2220        validPrimitive = validUnit(value, FNumber);
2221        break;
2222    case CSSPropertyWebkitBoxFlexGroup:
2223        validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode);
2224        break;
2225    case CSSPropertyWebkitBoxOrdinalGroup:
2226        validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode) && value->fValue;
2227        break;
2228    case CSSPropertyWebkitFilter:
2229        if (id == CSSValueNone)
2230            validPrimitive = true;
2231        else {
2232            RefPtr<CSSValue> val = parseFilter();
2233            if (val) {
2234                addProperty(propId, val, important);
2235                return true;
2236            }
2237            return false;
2238        }
2239        break;
2240    case CSSPropertyFlex: {
2241        ShorthandScope scope(this, propId);
2242        if (id == CSSValueNone) {
2243            addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
2244            addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
2245            addProperty(CSSPropertyFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
2246            return true;
2247        }
2248        return parseFlex(m_valueList.get(), important);
2249    }
2250    case CSSPropertyFlexBasis:
2251        // FIXME: Support intrinsic dimensions too.
2252        if (id == CSSValueAuto)
2253            validPrimitive = true;
2254        else
2255            validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
2256        break;
2257    case CSSPropertyFlexGrow:
2258    case CSSPropertyFlexShrink:
2259        validPrimitive = validUnit(value, FNumber | FNonNeg);
2260        break;
2261    case CSSPropertyOrder:
2262        if (validUnit(value, FInteger, HTMLStandardMode)) {
2263            if (value->unit != CSSPrimitiveValue::CSS_VARIABLE_NAME) {
2264                // We restrict the smallest value to int min + 2 because we use int min and int min + 1 as special values in a hash set.
2265                parsedValue = cssValuePool().createValue(max(static_cast<double>(std::numeric_limits<int>::min() + 2), value->fValue),
2266                    static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
2267                m_valueList->next();
2268            } else {
2269                validPrimitive = true;
2270            }
2271        }
2272        break;
2273    case CSSPropertyInternalMarqueeIncrement:
2274        if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
2275            validPrimitive = true;
2276        else
2277            validPrimitive = validUnit(value, FLength | FPercent);
2278        break;
2279    case CSSPropertyInternalMarqueeRepetition:
2280        if (id == CSSValueInfinite)
2281            validPrimitive = true;
2282        else
2283            validPrimitive = validUnit(value, FInteger | FNonNeg);
2284        break;
2285    case CSSPropertyInternalMarqueeSpeed:
2286        if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
2287            validPrimitive = true;
2288        else
2289            validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
2290        break;
2291    case CSSPropertyWebkitFlowInto:
2292        if (!RuntimeEnabledFeatures::cssRegionsEnabled())
2293            return false;
2294        return parseFlowThread(propId, important);
2295    case CSSPropertyWebkitFlowFrom:
2296        if (!RuntimeEnabledFeatures::cssRegionsEnabled())
2297            return false;
2298        return parseRegionThread(propId, important);
2299    case CSSPropertyWebkitTransform:
2300        if (id == CSSValueNone)
2301            validPrimitive = true;
2302        else {
2303            RefPtr<CSSValue> transformValue = parseTransform();
2304            if (transformValue) {
2305                addProperty(propId, transformValue.release(), important);
2306                return true;
2307            }
2308            return false;
2309        }
2310        break;
2311    case CSSPropertyWebkitTransformOrigin:
2312    case CSSPropertyWebkitTransformOriginX:
2313    case CSSPropertyWebkitTransformOriginY:
2314    case CSSPropertyWebkitTransformOriginZ: {
2315        RefPtr<CSSValue> val1;
2316        RefPtr<CSSValue> val2;
2317        RefPtr<CSSValue> val3;
2318        CSSPropertyID propId1, propId2, propId3;
2319        if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
2320            addProperty(propId1, val1.release(), important);
2321            if (val2)
2322                addProperty(propId2, val2.release(), important);
2323            if (val3)
2324                addProperty(propId3, val3.release(), important);
2325            return true;
2326        }
2327        return false;
2328    }
2329    case CSSPropertyWebkitPerspective:
2330        if (id == CSSValueNone)
2331            validPrimitive = true;
2332        else {
2333            // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
2334            if (validUnit(value, FNumber | FLength | FNonNeg)) {
2335                RefPtr<CSSValue> val = createPrimitiveNumericValue(value);
2336                if (val) {
2337                    addProperty(propId, val.release(), important);
2338                    return true;
2339                }
2340                return false;
2341            }
2342        }
2343        break;
2344    case CSSPropertyWebkitPerspectiveOrigin:
2345    case CSSPropertyWebkitPerspectiveOriginX:
2346    case CSSPropertyWebkitPerspectiveOriginY: {
2347        RefPtr<CSSValue> val1;
2348        RefPtr<CSSValue> val2;
2349        CSSPropertyID propId1, propId2;
2350        if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
2351            addProperty(propId1, val1.release(), important);
2352            if (val2)
2353                addProperty(propId2, val2.release(), important);
2354            return true;
2355        }
2356        return false;
2357    }
2358    case CSSPropertyAnimationDelay:
2359    case CSSPropertyAnimationDirection:
2360    case CSSPropertyAnimationDuration:
2361    case CSSPropertyAnimationFillMode:
2362    case CSSPropertyAnimationName:
2363    case CSSPropertyAnimationPlayState:
2364    case CSSPropertyAnimationIterationCount:
2365    case CSSPropertyAnimationTimingFunction:
2366        if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
2367            break;
2368    case CSSPropertyWebkitAnimationDelay:
2369    case CSSPropertyWebkitAnimationDirection:
2370    case CSSPropertyWebkitAnimationDuration:
2371    case CSSPropertyWebkitAnimationFillMode:
2372    case CSSPropertyWebkitAnimationName:
2373    case CSSPropertyWebkitAnimationPlayState:
2374    case CSSPropertyWebkitAnimationIterationCount:
2375    case CSSPropertyWebkitAnimationTimingFunction:
2376    case CSSPropertyTransitionDelay:
2377    case CSSPropertyTransitionDuration:
2378    case CSSPropertyTransitionTimingFunction:
2379    case CSSPropertyTransitionProperty:
2380    case CSSPropertyWebkitTransitionDelay:
2381    case CSSPropertyWebkitTransitionDuration:
2382    case CSSPropertyWebkitTransitionTimingFunction:
2383    case CSSPropertyWebkitTransitionProperty: {
2384        RefPtr<CSSValue> val;
2385        AnimationParseContext context;
2386        if (parseAnimationProperty(propId, val, context)) {
2387            addPropertyWithPrefixingVariant(propId, val.release(), important);
2388            return true;
2389        }
2390        return false;
2391    }
2392
2393    case CSSPropertyGridAutoColumns:
2394    case CSSPropertyGridAutoRows:
2395        if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2396            return false;
2397        parsedValue = parseGridTrackSize(*m_valueList);
2398        break;
2399
2400    case CSSPropertyGridDefinitionColumns:
2401    case CSSPropertyGridDefinitionRows:
2402        if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2403            return false;
2404        return parseGridTrackList(propId, important);
2405
2406    case CSSPropertyGridColumnEnd:
2407    case CSSPropertyGridColumnStart:
2408    case CSSPropertyGridRowEnd:
2409    case CSSPropertyGridRowStart:
2410        if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2411            return false;
2412        parsedValue = parseGridPosition();
2413        break;
2414
2415    case CSSPropertyGridColumn:
2416    case CSSPropertyGridRow:
2417        if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2418            return false;
2419        return parseGridItemPositionShorthand(propId, important);
2420
2421    case CSSPropertyGridArea:
2422        if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2423            return false;
2424        return parseGridAreaShorthand(important);
2425
2426    case CSSPropertyGridTemplate:
2427        if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2428            return false;
2429        parsedValue = parseGridTemplate();
2430        break;
2431
2432    case CSSPropertyWebkitMarginCollapse: {
2433        if (num == 1) {
2434            ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2435            if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important))
2436                return false;
2437            CSSValue* value = m_parsedProperties.last().value();
2438            addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
2439            return true;
2440        }
2441        else if (num == 2) {
2442            ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2443            if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important) || !parseValue(webkitMarginCollapseShorthand().properties()[1], important))
2444                return false;
2445            return true;
2446        }
2447        return false;
2448    }
2449    case CSSPropertyTextLineThroughWidth:
2450    case CSSPropertyTextOverlineWidth:
2451    case CSSPropertyTextUnderlineWidth:
2452        if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
2453            id == CSSValueMedium || id == CSSValueThick)
2454            validPrimitive = true;
2455        else
2456            validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent);
2457        break;
2458    case CSSPropertyWebkitColumnCount:
2459        parsedValue = parseColumnCount();
2460        break;
2461    case CSSPropertyWebkitColumnGap:         // normal | <length>
2462        if (id == CSSValueNormal)
2463            validPrimitive = true;
2464        else
2465            validPrimitive = validUnit(value, FLength | FNonNeg);
2466        break;
2467    case CSSPropertyWebkitColumnAxis:
2468        if (id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
2469            validPrimitive = true;
2470        break;
2471    case CSSPropertyWebkitColumnProgression:
2472        if (id == CSSValueNormal || id == CSSValueReverse)
2473            validPrimitive = true;
2474        break;
2475    case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property)
2476        if (id == CSSValueAll || id == CSSValueNone)
2477            validPrimitive = true;
2478        else
2479            validPrimitive = validUnit(value, FNumber | FNonNeg) && value->fValue == 1;
2480        break;
2481    case CSSPropertyWebkitColumnWidth:         // auto | <length>
2482        parsedValue = parseColumnWidth();
2483        break;
2484    // End of CSS3 properties
2485
2486    // Apple specific properties.  These will never be standardized and are purely to
2487    // support custom WebKit-based Apple applications.
2488    case CSSPropertyWebkitLineClamp:
2489        // When specifying number of lines, don't allow 0 as a valid value
2490        // When specifying either type of unit, require non-negative integers
2491        validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, HTMLQuirksMode));
2492        break;
2493
2494    case CSSPropertyWebkitFontSizeDelta:           // <length>
2495        validPrimitive = validUnit(value, FLength);
2496        break;
2497
2498    case CSSPropertyWebkitHighlight:
2499        if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
2500            validPrimitive = true;
2501        break;
2502
2503    case CSSPropertyWebkitHyphenateCharacter:
2504        if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2505            validPrimitive = true;
2506        break;
2507
2508    case CSSPropertyWebkitLineGrid:
2509        if (id == CSSValueNone)
2510            validPrimitive = true;
2511        else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
2512            String lineGridValue = String(value->string);
2513            if (!lineGridValue.isEmpty()) {
2514                addProperty(propId, cssValuePool().createValue(lineGridValue, CSSPrimitiveValue::CSS_STRING), important);
2515                return true;
2516            }
2517        }
2518        break;
2519    case CSSPropertyWebkitLocale:
2520        if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2521            validPrimitive = true;
2522        break;
2523
2524    // End Apple-specific properties
2525
2526    case CSSPropertyWebkitAppRegion:
2527        if (id >= CSSValueDrag && id <= CSSValueNoDrag)
2528            validPrimitive = true;
2529        break;
2530
2531    case CSSPropertyWebkitTapHighlightColor:
2532        if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu
2533            || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
2534            validPrimitive = true;
2535        } else {
2536            parsedValue = parseColor();
2537            if (parsedValue)
2538                m_valueList->next();
2539        }
2540        break;
2541
2542        /* shorthand properties */
2543    case CSSPropertyBackground: {
2544        // Position must come before color in this array because a plain old "0" is a legal color
2545        // in quirks mode but it's usually the X coordinate of a position.
2546        const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
2547                                   CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
2548                                   CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
2549        return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
2550    }
2551    case CSSPropertyWebkitMask: {
2552        const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
2553            CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize };
2554        return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
2555    }
2556    case CSSPropertyBorder:
2557        // [ 'border-width' || 'border-style' || <color> ] | inherit
2558    {
2559        if (parseShorthand(propId, parsingShorthandForProperty(CSSPropertyBorder), important)) {
2560            // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as
2561            // though a value of none was specified for the image.
2562            addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
2563            return true;
2564        }
2565        return false;
2566    }
2567    case CSSPropertyBorderTop:
2568        // [ 'border-top-width' || 'border-style' || <color> ] | inherit
2569        return parseShorthand(propId, borderTopShorthand(), important);
2570    case CSSPropertyBorderRight:
2571        // [ 'border-right-width' || 'border-style' || <color> ] | inherit
2572        return parseShorthand(propId, borderRightShorthand(), important);
2573    case CSSPropertyBorderBottom:
2574        // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
2575        return parseShorthand(propId, borderBottomShorthand(), important);
2576    case CSSPropertyBorderLeft:
2577        // [ 'border-left-width' || 'border-style' || <color> ] | inherit
2578        return parseShorthand(propId, borderLeftShorthand(), important);
2579    case CSSPropertyWebkitBorderStart:
2580        return parseShorthand(propId, webkitBorderStartShorthand(), important);
2581    case CSSPropertyWebkitBorderEnd:
2582        return parseShorthand(propId, webkitBorderEndShorthand(), important);
2583    case CSSPropertyWebkitBorderBefore:
2584        return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
2585    case CSSPropertyWebkitBorderAfter:
2586        return parseShorthand(propId, webkitBorderAfterShorthand(), important);
2587    case CSSPropertyOutline:
2588        // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
2589        return parseShorthand(propId, outlineShorthand(), important);
2590    case CSSPropertyBorderColor:
2591        // <color>{1,4} | inherit
2592        return parse4Values(propId, borderColorShorthand().properties(), important);
2593    case CSSPropertyBorderWidth:
2594        // <border-width>{1,4} | inherit
2595        return parse4Values(propId, borderWidthShorthand().properties(), important);
2596    case CSSPropertyBorderStyle:
2597        // <border-style>{1,4} | inherit
2598        return parse4Values(propId, borderStyleShorthand().properties(), important);
2599    case CSSPropertyMargin:
2600        // <margin-width>{1,4} | inherit
2601        return parse4Values(propId, marginShorthand().properties(), important);
2602    case CSSPropertyPadding:
2603        // <padding-width>{1,4} | inherit
2604        return parse4Values(propId, paddingShorthand().properties(), important);
2605    case CSSPropertyFlexFlow:
2606        return parseShorthand(propId, flexFlowShorthand(), important);
2607    case CSSPropertyFont:
2608        // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
2609        // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
2610        if (id >= CSSValueCaption && id <= CSSValueStatusBar)
2611            validPrimitive = true;
2612        else
2613            return parseFont(important);
2614        break;
2615    case CSSPropertyListStyle:
2616        return parseShorthand(propId, listStyleShorthand(), important);
2617    case CSSPropertyWebkitColumns:
2618        return parseColumnsShorthand(important);
2619    case CSSPropertyWebkitColumnRule:
2620        return parseShorthand(propId, webkitColumnRuleShorthand(), important);
2621    case CSSPropertyWebkitTextStroke:
2622        return parseShorthand(propId, webkitTextStrokeShorthand(), important);
2623    case CSSPropertyAnimation:
2624        if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
2625            break;
2626    case CSSPropertyWebkitAnimation:
2627        return parseAnimationShorthand(propId, important);
2628    case CSSPropertyTransition:
2629    case CSSPropertyWebkitTransition:
2630        return parseTransitionShorthand(propId, important);
2631    case CSSPropertyInvalid:
2632        return false;
2633    case CSSPropertyPage:
2634        return parsePage(propId, important);
2635    case CSSPropertyFontStretch:
2636        return false;
2637    // CSS Text Layout Module Level 3: Vertical writing support
2638    case CSSPropertyWebkitTextEmphasis:
2639        return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
2640
2641    case CSSPropertyWebkitTextEmphasisStyle:
2642        return parseTextEmphasisStyle(important);
2643
2644    case CSSPropertyWebkitTextOrientation:
2645        // FIXME: For now just support sideways, sideways-right, upright and vertical-right.
2646        if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSValueVerticalRight || id == CSSValueUpright)
2647            validPrimitive = true;
2648        break;
2649
2650    case CSSPropertyWebkitLineBoxContain:
2651        if (id == CSSValueNone)
2652            validPrimitive = true;
2653        else
2654            return parseLineBoxContain(important);
2655        break;
2656    case CSSPropertyWebkitFontFeatureSettings:
2657        if (id == CSSValueNormal)
2658            validPrimitive = true;
2659        else
2660            return parseFontFeatureSettings(important);
2661        break;
2662
2663    case CSSPropertyWebkitFontVariantLigatures:
2664        if (id == CSSValueNormal)
2665            validPrimitive = true;
2666        else
2667            return parseFontVariantLigatures(important);
2668        break;
2669    case CSSPropertyWebkitClipPath:
2670        if (id == CSSValueNone) {
2671            validPrimitive = true;
2672        } else if (value->unit == CSSParserValue::Function) {
2673            return parseBasicShape(propId, important);
2674        } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
2675            parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
2676            addProperty(propId, parsedValue.release(), important);
2677            return true;
2678        }
2679        break;
2680    case CSSPropertyShapeInside:
2681    case CSSPropertyShapeOutside:
2682        if (!RuntimeEnabledFeatures::cssShapesEnabled())
2683            return false;
2684        if (id == CSSValueAuto)
2685            validPrimitive = true;
2686        else if (id == CSSValueContentBox || id == CSSValuePaddingBox || id == CSSValueBorderBox || id == CSSValueMarginBox)
2687            validPrimitive = true;
2688        else if (propId == CSSPropertyShapeInside && id == CSSValueOutsideShape)
2689            validPrimitive = true;
2690        else if (value->unit == CSSParserValue::Function)
2691            return parseBasicShape(propId, important);
2692        else if (value->unit == CSSPrimitiveValue::CSS_URI) {
2693            parsedValue = CSSImageValue::create(completeURL(value->string));
2694            m_valueList->next();
2695        }
2696        break;
2697    case CSSPropertyShapeMargin:
2698    case CSSPropertyShapePadding:
2699        validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FLength | FNonNeg));
2700        break;
2701    case CSSPropertyShapeImageThreshold:
2702        validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FNumber));
2703        break;
2704
2705    case CSSPropertyTouchAction:
2706        // auto | none | [pan-x || pan-y]
2707        return parseTouchAction(important);
2708
2709    case CSSPropertyBorderBottomStyle:
2710    case CSSPropertyBorderCollapse:
2711    case CSSPropertyBorderLeftStyle:
2712    case CSSPropertyBorderRightStyle:
2713    case CSSPropertyBorderTopStyle:
2714    case CSSPropertyBoxSizing:
2715    case CSSPropertyCaptionSide:
2716    case CSSPropertyClear:
2717    case CSSPropertyDirection:
2718    case CSSPropertyDisplay:
2719    case CSSPropertyEmptyCells:
2720    case CSSPropertyFloat:
2721    case CSSPropertyFontStyle:
2722    case CSSPropertyImageRendering:
2723    case CSSPropertyListStylePosition:
2724    case CSSPropertyListStyleType:
2725    case CSSPropertyObjectFit:
2726    case CSSPropertyOutlineStyle:
2727    case CSSPropertyOverflowWrap:
2728    case CSSPropertyOverflowX:
2729    case CSSPropertyOverflowY:
2730    case CSSPropertyPageBreakAfter:
2731    case CSSPropertyPageBreakBefore:
2732    case CSSPropertyPageBreakInside:
2733    case CSSPropertyPointerEvents:
2734    case CSSPropertyPosition:
2735    case CSSPropertyResize:
2736    case CSSPropertySpeak:
2737    case CSSPropertyTableLayout:
2738    case CSSPropertyTextAlignLast:
2739    case CSSPropertyTextJustify:
2740    case CSSPropertyTextLineThroughMode:
2741    case CSSPropertyTextLineThroughStyle:
2742    case CSSPropertyTextOverflow:
2743    case CSSPropertyTextOverlineMode:
2744    case CSSPropertyTextOverlineStyle:
2745    case CSSPropertyTextRendering:
2746    case CSSPropertyTextTransform:
2747    case CSSPropertyTextUnderlineMode:
2748    case CSSPropertyTextUnderlineStyle:
2749    case CSSPropertyTouchActionDelay:
2750    case CSSPropertyVariable:
2751    case CSSPropertyVisibility:
2752    case CSSPropertyWebkitAppearance:
2753    case CSSPropertyWebkitBackfaceVisibility:
2754    case CSSPropertyWebkitBorderAfterStyle:
2755    case CSSPropertyWebkitBorderBeforeStyle:
2756    case CSSPropertyWebkitBorderEndStyle:
2757    case CSSPropertyWebkitBorderFit:
2758    case CSSPropertyWebkitBorderStartStyle:
2759    case CSSPropertyWebkitBoxAlign:
2760    case CSSPropertyWebkitBoxDecorationBreak:
2761    case CSSPropertyWebkitBoxDirection:
2762    case CSSPropertyWebkitBoxLines:
2763    case CSSPropertyWebkitBoxOrient:
2764    case CSSPropertyWebkitBoxPack:
2765    case CSSPropertyInternalCallback:
2766    case CSSPropertyWebkitColumnBreakAfter:
2767    case CSSPropertyWebkitColumnBreakBefore:
2768    case CSSPropertyWebkitColumnBreakInside:
2769    case CSSPropertyColumnFill:
2770    case CSSPropertyWebkitColumnRuleStyle:
2771    case CSSPropertyAlignContent:
2772    case CSSPropertyAlignItems:
2773    case CSSPropertyAlignSelf:
2774    case CSSPropertyFlexDirection:
2775    case CSSPropertyFlexWrap:
2776    case CSSPropertyJustifyContent:
2777    case CSSPropertyFontKerning:
2778    case CSSPropertyWebkitFontSmoothing:
2779    case CSSPropertyGridAutoFlow:
2780    case CSSPropertyWebkitLineAlign:
2781    case CSSPropertyWebkitLineBreak:
2782    case CSSPropertyWebkitLineSnap:
2783    case CSSPropertyWebkitMarginAfterCollapse:
2784    case CSSPropertyWebkitMarginBeforeCollapse:
2785    case CSSPropertyWebkitMarginBottomCollapse:
2786    case CSSPropertyWebkitMarginTopCollapse:
2787    case CSSPropertyInternalMarqueeDirection:
2788    case CSSPropertyInternalMarqueeStyle:
2789    case CSSPropertyWebkitPrintColorAdjust:
2790    case CSSPropertyWebkitRegionBreakAfter:
2791    case CSSPropertyWebkitRegionBreakBefore:
2792    case CSSPropertyWebkitRegionBreakInside:
2793    case CSSPropertyWebkitRegionFragment:
2794    case CSSPropertyWebkitRtlOrdering:
2795    case CSSPropertyWebkitRubyPosition:
2796    case CSSPropertyWebkitTextCombine:
2797    case CSSPropertyWebkitTextEmphasisPosition:
2798    case CSSPropertyWebkitTextSecurity:
2799    case CSSPropertyWebkitTransformStyle:
2800    case CSSPropertyWebkitUserDrag:
2801    case CSSPropertyWebkitUserModify:
2802    case CSSPropertyWebkitUserSelect:
2803    case CSSPropertyWebkitWrapFlow:
2804    case CSSPropertyWebkitWrapThrough:
2805    case CSSPropertyWebkitWritingMode:
2806    case CSSPropertyWhiteSpace:
2807    case CSSPropertyWordBreak:
2808    case CSSPropertyWordWrap:
2809    case CSSPropertyMixBlendMode:
2810    case CSSPropertyIsolation:
2811        // These properties should be handled before in isValidKeywordPropertyAndValue().
2812        ASSERT_NOT_REACHED();
2813        return false;
2814    // Properties below are validated inside parseViewportProperty, because we
2815    // check for parser state. We need to invalidate if someone adds them outside
2816    // a @viewport rule.
2817    case CSSPropertyMaxZoom:
2818    case CSSPropertyMinZoom:
2819    case CSSPropertyOrientation:
2820    case CSSPropertyUserZoom:
2821        validPrimitive = false;
2822        break;
2823    default:
2824        return parseSVGValue(propId, important);
2825    }
2826
2827    if (validPrimitive) {
2828        parsedValue = parseValidPrimitive(id, value);
2829        m_valueList->next();
2830    }
2831    ASSERT(!m_parsedCalculation);
2832    if (parsedValue) {
2833        if (!m_valueList->current() || inShorthand()) {
2834            addProperty(propId, parsedValue.release(), important);
2835            return true;
2836        }
2837    }
2838    return false;
2839}
2840
2841void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
2842{
2843    if (lval) {
2844        if (lval->isBaseValueList())
2845            toCSSValueList(lval.get())->append(rval);
2846        else {
2847            PassRefPtr<CSSValue> oldlVal(lval.release());
2848            PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
2849            list->append(oldlVal);
2850            list->append(rval);
2851            lval = list;
2852        }
2853    }
2854    else
2855        lval = rval;
2856}
2857
2858static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue)
2859{
2860    if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
2861        || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
2862        cssValue = cssValuePool().createIdentifierValue(parserValue->id);
2863        return true;
2864    }
2865    return false;
2866}
2867
2868bool CSSParser::useLegacyBackgroundSizeShorthandBehavior() const
2869{
2870    return m_context.useLegacyBackgroundSizeShorthandBehavior();
2871}
2872
2873const int cMaxFillProperties = 9;
2874
2875bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
2876{
2877    ASSERT(numProperties <= cMaxFillProperties);
2878    if (numProperties > cMaxFillProperties)
2879        return false;
2880
2881    ShorthandScope scope(this, propId);
2882
2883    bool parsedProperty[cMaxFillProperties] = { false };
2884    RefPtr<CSSValue> values[cMaxFillProperties];
2885    RefPtr<CSSValue> clipValue;
2886    RefPtr<CSSValue> positionYValue;
2887    RefPtr<CSSValue> repeatYValue;
2888    bool foundClip = false;
2889    int i;
2890    bool foundPositionCSSProperty = false;
2891
2892    while (m_valueList->current()) {
2893        CSSParserValue* val = m_valueList->current();
2894        if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
2895            // We hit the end.  Fill in all remaining values with the initial value.
2896            m_valueList->next();
2897            for (i = 0; i < numProperties; ++i) {
2898                if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
2899                    // Color is not allowed except as the last item in a list for backgrounds.
2900                    // Reject the entire property.
2901                    return false;
2902
2903                if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
2904                    addFillValue(values[i], cssValuePool().createImplicitInitialValue());
2905                    if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2906                        addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
2907                    if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2908                        addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
2909                    if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
2910                        // If background-origin wasn't present, then reset background-clip also.
2911                        addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
2912                    }
2913                }
2914                parsedProperty[i] = false;
2915            }
2916            if (!m_valueList->current())
2917                break;
2918        }
2919
2920        bool sizeCSSPropertyExpected = false;
2921        if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
2922            sizeCSSPropertyExpected = true;
2923            m_valueList->next();
2924        }
2925
2926        foundPositionCSSProperty = false;
2927        bool found = false;
2928        for (i = 0; !found && i < numProperties; ++i) {
2929
2930            if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgroundSize && properties[i] != CSSPropertyWebkitMaskSize))
2931                continue;
2932            if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgroundSize || properties[i] == CSSPropertyWebkitMaskSize))
2933                continue;
2934
2935            if (!parsedProperty[i]) {
2936                RefPtr<CSSValue> val1;
2937                RefPtr<CSSValue> val2;
2938                CSSPropertyID propId1, propId2;
2939                CSSParserValue* parserValue = m_valueList->current();
2940                // parseFillProperty() may modify m_implicitShorthand, so we MUST reset it
2941                // before EACH return below.
2942                if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
2943                    parsedProperty[i] = found = true;
2944                    addFillValue(values[i], val1.release());
2945                    if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2946                        addFillValue(positionYValue, val2.release());
2947                    if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2948                        addFillValue(repeatYValue, val2.release());
2949                    if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
2950                        // Reparse the value as a clip, and see if we succeed.
2951                        if (parseBackgroundClip(parserValue, val1))
2952                            addFillValue(clipValue, val1.release()); // The property parsed successfully.
2953                        else
2954                            addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
2955                    }
2956                    if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
2957                        // Update clipValue
2958                        addFillValue(clipValue, val1.release());
2959                        foundClip = true;
2960                    }
2961                    if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2962                        foundPositionCSSProperty = true;
2963                }
2964            }
2965        }
2966
2967        // if we didn't find at least one match, this is an
2968        // invalid shorthand and we have to ignore it
2969        if (!found) {
2970            m_implicitShorthand = false;
2971            return false;
2972        }
2973    }
2974
2975    // Now add all of the properties we found.
2976    for (i = 0; i < numProperties; i++) {
2977        // Fill in any remaining properties with the initial value.
2978        if (!parsedProperty[i]) {
2979            addFillValue(values[i], cssValuePool().createImplicitInitialValue());
2980            if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2981                addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
2982            if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2983                addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
2984            if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
2985                // If background-origin wasn't present, then reset background-clip also.
2986                addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
2987            }
2988        }
2989        if (properties[i] == CSSPropertyBackgroundPosition) {
2990            addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
2991            // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
2992            addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
2993        } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
2994            addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
2995            // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
2996            addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
2997        } else if (properties[i] == CSSPropertyBackgroundRepeat) {
2998            addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
2999            // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
3000            addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
3001        } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
3002            addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
3003            // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
3004            addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
3005        } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
3006            // Value is already set while updating origin
3007            continue;
3008        else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i] && useLegacyBackgroundSizeShorthandBehavior())
3009            continue;
3010        else
3011            addProperty(properties[i], values[i].release(), important);
3012
3013        // Add in clip values when we hit the corresponding origin property.
3014        if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
3015            addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
3016        else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
3017            addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
3018    }
3019
3020    m_implicitShorthand = false;
3021    return true;
3022}
3023
3024void CSSParser::storeVariableDeclaration(const CSSParserString& name, PassOwnPtr<CSSParserValueList> value, bool important)
3025{
3026    // When CSSGrammar.y encounters an invalid declaration it passes null for the CSSParserValueList, just bail.
3027    if (!value)
3028        return;
3029
3030    static const unsigned prefixLength = sizeof("var-") - 1;
3031
3032    ASSERT(name.length() > prefixLength);
3033    AtomicString variableName = name.atomicSubstring(prefixLength, name.length() - prefixLength);
3034
3035    StringBuilder builder;
3036    for (unsigned i = 0, size = value->size(); i < size; i++) {
3037        if (i)
3038            builder.append(' ');
3039        RefPtr<CSSValue> cssValue = value->valueAt(i)->createCSSValue();
3040        if (!cssValue)
3041            return;
3042        builder.append(cssValue->cssText());
3043    }
3044
3045    addProperty(CSSPropertyVariable, CSSVariableValue::create(variableName, builder.toString()), important, false);
3046}
3047
3048void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
3049{
3050    if (lval) {
3051        if (lval->isValueList())
3052            toCSSValueList(lval.get())->append(rval);
3053        else {
3054            PassRefPtr<CSSValue> oldVal(lval.release());
3055            PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
3056            list->append(oldVal);
3057            list->append(rval);
3058            lval = list;
3059        }
3060    }
3061    else
3062        lval = rval;
3063}
3064
3065bool CSSParser::parseAnimationShorthand(CSSPropertyID propId, bool important)
3066{
3067    const StylePropertyShorthand& animationProperties = parsingShorthandForProperty(propId);
3068    const unsigned numProperties = 8;
3069
3070    // The list of properties in the shorthand should be the same
3071    // length as the list with animation name in last position, even though they are
3072    // in a different order.
3073    ASSERT(numProperties == animationProperties.length());
3074    ASSERT(numProperties == shorthandForProperty(propId).length());
3075
3076    ShorthandScope scope(this, propId);
3077
3078    bool parsedProperty[numProperties] = { false };
3079    AnimationParseContext context;
3080    RefPtr<CSSValue> values[numProperties];
3081
3082    unsigned i;
3083    while (m_valueList->current()) {
3084        CSSParserValue* val = m_valueList->current();
3085        if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3086            // We hit the end.  Fill in all remaining values with the initial value.
3087            m_valueList->next();
3088            for (i = 0; i < numProperties; ++i) {
3089                if (!parsedProperty[i])
3090                    addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3091                parsedProperty[i] = false;
3092            }
3093            if (!m_valueList->current())
3094                break;
3095            context.commitFirstAnimation();
3096        }
3097
3098        bool found = false;
3099        for (i = 0; i < numProperties; ++i) {
3100            if (!parsedProperty[i]) {
3101                RefPtr<CSSValue> val;
3102                if (parseAnimationProperty(animationProperties.properties()[i], val, context)) {
3103                    parsedProperty[i] = found = true;
3104                    addAnimationValue(values[i], val.release());
3105                    break;
3106                }
3107            }
3108        }
3109
3110        // if we didn't find at least one match, this is an
3111        // invalid shorthand and we have to ignore it
3112        if (!found)
3113            return false;
3114    }
3115
3116    for (i = 0; i < numProperties; ++i) {
3117        // If we didn't find the property, set an intial value.
3118        if (!parsedProperty[i])
3119            addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3120
3121        addProperty(animationProperties.properties()[i], values[i].release(), important);
3122    }
3123
3124    return true;
3125}
3126
3127bool CSSParser::parseTransitionShorthand(CSSPropertyID propId, bool important)
3128{
3129    const unsigned numProperties = 4;
3130    const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
3131    ASSERT(numProperties == shorthand.length());
3132
3133    ShorthandScope scope(this, propId);
3134
3135    bool parsedProperty[numProperties] = { false };
3136    AnimationParseContext context;
3137    RefPtr<CSSValue> values[numProperties];
3138
3139    unsigned i;
3140    while (m_valueList->current()) {
3141        CSSParserValue* val = m_valueList->current();
3142        if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3143            // We hit the end. Fill in all remaining values with the initial value.
3144            m_valueList->next();
3145            for (i = 0; i < numProperties; ++i) {
3146                if (!parsedProperty[i])
3147                    addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3148                parsedProperty[i] = false;
3149            }
3150            if (!m_valueList->current())
3151                break;
3152            context.commitFirstAnimation();
3153        }
3154
3155        bool found = false;
3156        for (i = 0; !found && i < numProperties; ++i) {
3157            if (!parsedProperty[i]) {
3158                RefPtr<CSSValue> val;
3159                if (parseAnimationProperty(shorthand.properties()[i], val, context)) {
3160                    parsedProperty[i] = found = true;
3161                    addAnimationValue(values[i], val.release());
3162                }
3163
3164                // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid.
3165                if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation())
3166                    return false;
3167            }
3168        }
3169
3170        // if we didn't find at least one match, this is an
3171        // invalid shorthand and we have to ignore it
3172        if (!found)
3173            return false;
3174    }
3175
3176    // Fill in any remaining properties with the initial value.
3177    for (i = 0; i < numProperties; ++i) {
3178        if (!parsedProperty[i])
3179            addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3180    }
3181
3182    // Now add all of the properties we found.
3183    for (i = 0; i < numProperties; i++)
3184        addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].release(), important);
3185
3186    return true;
3187}
3188
3189PassRefPtr<CSSValue> CSSParser::parseColumnWidth()
3190{
3191    CSSParserValue* value = m_valueList->current();
3192    // Always parse lengths in strict mode here, since it would be ambiguous otherwise when used in
3193    // the 'columns' shorthand property.
3194    if (value->id == CSSValueAuto
3195        || (validUnit(value, FLength | FNonNeg, HTMLStandardMode) && value->fValue)) {
3196        RefPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
3197        m_valueList->next();
3198        return parsedValue;
3199    }
3200    return 0;
3201}
3202
3203PassRefPtr<CSSValue> CSSParser::parseColumnCount()
3204{
3205    CSSParserValue* value = m_valueList->current();
3206    if (value->id == CSSValueAuto
3207        || (!value->id && validUnit(value, FPositiveInteger, HTMLQuirksMode))) {
3208        RefPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
3209        m_valueList->next();
3210        return parsedValue;
3211    }
3212    return 0;
3213}
3214
3215bool CSSParser::parseColumnsShorthand(bool important)
3216{
3217    RefPtr <CSSValue> columnWidth;
3218    RefPtr <CSSValue> columnCount;
3219    bool hasPendingExplicitAuto = false;
3220
3221    for (unsigned propertiesParsed = 0; CSSParserValue* value = m_valueList->current(); propertiesParsed++) {
3222        if (propertiesParsed >= 2)
3223            return false; // Too many values for this shorthand. Invalid declaration.
3224        if (!propertiesParsed && value->id == CSSValueAuto) {
3225            // 'auto' is a valid value for any of the two longhands, and at this point we
3226            // don't know which one(s) it is meant for. We need to see if there are other
3227            // values first.
3228            m_valueList->next();
3229            hasPendingExplicitAuto = true;
3230        } else {
3231            if (!columnWidth) {
3232                if ((columnWidth = parseColumnWidth()))
3233                    continue;
3234            }
3235            if (!columnCount) {
3236                if ((columnCount = parseColumnCount()))
3237                    continue;
3238            }
3239            // If we didn't find at least one match, this is an
3240            // invalid shorthand and we have to ignore it.
3241            return false;
3242        }
3243    }
3244    if (hasPendingExplicitAuto) {
3245        // Time to assign the previously skipped 'auto' value to a property. If both properties are
3246        // unassigned at this point (i.e. 'columns:auto'), it doesn't matter that much which one we
3247        // set (although it does make a slight difference to web-inspector). The one we don't set
3248        // here will get an implicit 'auto' value further down.
3249        if (!columnWidth) {
3250            columnWidth = cssValuePool().createIdentifierValue(CSSValueAuto);
3251        } else {
3252            ASSERT(!columnCount);
3253            columnCount = cssValuePool().createIdentifierValue(CSSValueAuto);
3254        }
3255    }
3256    ASSERT(columnCount || columnWidth);
3257
3258    // Any unassigned property at this point will become implicit 'auto'.
3259    if (columnWidth)
3260        addProperty(CSSPropertyWebkitColumnWidth, columnWidth, important);
3261    else
3262        addProperty(CSSPropertyWebkitColumnWidth, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
3263    if (columnCount)
3264        addProperty(CSSPropertyWebkitColumnCount, columnCount, important);
3265    else
3266        addProperty(CSSPropertyWebkitColumnCount, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
3267    return true;
3268}
3269
3270bool CSSParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
3271{
3272    // We try to match as many properties as possible
3273    // We set up an array of booleans to mark which property has been found,
3274    // and we try to search for properties until it makes no longer any sense.
3275    ShorthandScope scope(this, propId);
3276
3277    bool found = false;
3278    unsigned propertiesParsed = 0;
3279    bool propertyFound[6]= { false, false, false, false, false, false }; // 6 is enough size.
3280
3281    while (m_valueList->current()) {
3282        found = false;
3283        for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
3284            if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
3285                    propertyFound[propIndex] = found = true;
3286                    propertiesParsed++;
3287            }
3288        }
3289
3290        // if we didn't find at least one match, this is an
3291        // invalid shorthand and we have to ignore it
3292        if (!found)
3293            return false;
3294    }
3295
3296    if (propertiesParsed == shorthand.length())
3297        return true;
3298
3299    // Fill in any remaining properties with the initial value.
3300    ImplicitScope implicitScope(this, PropertyImplicit);
3301    const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization();
3302    for (unsigned i = 0; i < shorthand.length(); ++i) {
3303        if (propertyFound[i])
3304            continue;
3305
3306        if (propertiesForInitialization) {
3307            const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]);
3308            for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
3309                addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
3310        } else
3311            addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
3312    }
3313
3314    return true;
3315}
3316
3317bool CSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties,  bool important)
3318{
3319    /* From the CSS 2 specs, 8.3
3320     * If there is only one value, it applies to all sides. If there are two values, the top and
3321     * bottom margins are set to the first value and the right and left margins are set to the second.
3322     * If there are three values, the top is set to the first value, the left and right are set to the
3323     * second, and the bottom is set to the third. If there are four values, they apply to the top,
3324     * right, bottom, and left, respectively.
3325     */
3326
3327    int num = inShorthand() ? 1 : m_valueList->size();
3328
3329    ShorthandScope scope(this, propId);
3330
3331    // the order is top, right, bottom, left
3332    switch (num) {
3333        case 1: {
3334            if (!parseValue(properties[0], important))
3335                return false;
3336            CSSValue* value = m_parsedProperties.last().value();
3337            ImplicitScope implicitScope(this, PropertyImplicit);
3338            addProperty(properties[1], value, important);
3339            addProperty(properties[2], value, important);
3340            addProperty(properties[3], value, important);
3341            break;
3342        }
3343        case 2: {
3344            if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
3345                return false;
3346            CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3347            ImplicitScope implicitScope(this, PropertyImplicit);
3348            addProperty(properties[2], value, important);
3349            value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3350            addProperty(properties[3], value, important);
3351            break;
3352        }
3353        case 3: {
3354            if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
3355                return false;
3356            CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3357            ImplicitScope implicitScope(this, PropertyImplicit);
3358            addProperty(properties[3], value, important);
3359            break;
3360        }
3361        case 4: {
3362            if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
3363                !parseValue(properties[2], important) || !parseValue(properties[3], important))
3364                return false;
3365            break;
3366        }
3367        default: {
3368            return false;
3369        }
3370    }
3371
3372    return true;
3373}
3374
3375// auto | <identifier>
3376bool CSSParser::parsePage(CSSPropertyID propId, bool important)
3377{
3378    ASSERT(propId == CSSPropertyPage);
3379
3380    if (m_valueList->size() != 1)
3381        return false;
3382
3383    CSSParserValue* value = m_valueList->current();
3384    if (!value)
3385        return false;
3386
3387    if (value->id == CSSValueAuto) {
3388        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
3389        return true;
3390    } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
3391        addProperty(propId, createPrimitiveStringValue(value), important);
3392        return true;
3393    }
3394    return false;
3395}
3396
3397// <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
3398bool CSSParser::parseSize(CSSPropertyID propId, bool important)
3399{
3400    ASSERT(propId == CSSPropertySize);
3401
3402    if (m_valueList->size() > 2)
3403        return false;
3404
3405    CSSParserValue* value = m_valueList->current();
3406    if (!value)
3407        return false;
3408
3409    RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
3410
3411    // First parameter.
3412    SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
3413    if (paramType == None)
3414        return false;
3415
3416    // Second parameter, if any.
3417    value = m_valueList->next();
3418    if (value) {
3419        paramType = parseSizeParameter(parsedValues.get(), value, paramType);
3420        if (paramType == None)
3421            return false;
3422    }
3423
3424    addProperty(propId, parsedValues.release(), important);
3425    return true;
3426}
3427
3428CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
3429{
3430    switch (value->id) {
3431    case CSSValueAuto:
3432        if (prevParamType == None) {
3433            parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3434            return Auto;
3435        }
3436        return None;
3437    case CSSValueLandscape:
3438    case CSSValuePortrait:
3439        if (prevParamType == None || prevParamType == PageSize) {
3440            parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3441            return Orientation;
3442        }
3443        return None;
3444    case CSSValueA3:
3445    case CSSValueA4:
3446    case CSSValueA5:
3447    case CSSValueB4:
3448    case CSSValueB5:
3449    case CSSValueLedger:
3450    case CSSValueLegal:
3451    case CSSValueLetter:
3452        if (prevParamType == None || prevParamType == Orientation) {
3453            // Normalize to Page Size then Orientation order by prepending.
3454            // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
3455            parsedValues->prepend(cssValuePool().createIdentifierValue(value->id));
3456            return PageSize;
3457        }
3458        return None;
3459    case 0:
3460        if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) {
3461            parsedValues->append(createPrimitiveNumericValue(value));
3462            return Length;
3463        }
3464        return None;
3465    default:
3466        return None;
3467    }
3468}
3469
3470// [ <string> <string> ]+ | inherit | none
3471// inherit and none are handled in parseValue.
3472bool CSSParser::parseQuotes(CSSPropertyID propId, bool important)
3473{
3474    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3475    while (CSSParserValue* val = m_valueList->current()) {
3476        RefPtr<CSSValue> parsedValue;
3477        if (val->unit == CSSPrimitiveValue::CSS_STRING)
3478            parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
3479        else
3480            break;
3481        values->append(parsedValue.release());
3482        m_valueList->next();
3483    }
3484    if (values->length()) {
3485        addProperty(propId, values.release(), important);
3486        m_valueList->next();
3487        return true;
3488    }
3489    return false;
3490}
3491
3492// [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
3493// in CSS 2.1 this got somewhat reduced:
3494// [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
3495bool CSSParser::parseContent(CSSPropertyID propId, bool important)
3496{
3497    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3498
3499    while (CSSParserValue* val = m_valueList->current()) {
3500        RefPtr<CSSValue> parsedValue;
3501        if (val->unit == CSSPrimitiveValue::CSS_URI) {
3502            // url
3503            parsedValue = CSSImageValue::create(completeURL(val->string));
3504        } else if (val->unit == CSSParserValue::Function) {
3505            // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
3506            CSSParserValueList* args = val->function->args.get();
3507            if (!args)
3508                return false;
3509            if (equalIgnoringCase(val->function->name, "attr(")) {
3510                parsedValue = parseAttr(args);
3511                if (!parsedValue)
3512                    return false;
3513            } else if (equalIgnoringCase(val->function->name, "counter(")) {
3514                parsedValue = parseCounterContent(args, false);
3515                if (!parsedValue)
3516                    return false;
3517            } else if (equalIgnoringCase(val->function->name, "counters(")) {
3518                parsedValue = parseCounterContent(args, true);
3519                if (!parsedValue)
3520                    return false;
3521            } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
3522                parsedValue = parseImageSet(m_valueList.get());
3523                if (!parsedValue)
3524                    return false;
3525            } else if (isGeneratedImageValue(val)) {
3526                if (!parseGeneratedImage(m_valueList.get(), parsedValue))
3527                    return false;
3528            } else
3529                return false;
3530        } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
3531            // open-quote
3532            // close-quote
3533            // no-open-quote
3534            // no-close-quote
3535            // inherit
3536            // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
3537            // none
3538            // normal
3539            switch (val->id) {
3540            case CSSValueOpenQuote:
3541            case CSSValueCloseQuote:
3542            case CSSValueNoOpenQuote:
3543            case CSSValueNoCloseQuote:
3544            case CSSValueNone:
3545            case CSSValueNormal:
3546                parsedValue = cssValuePool().createIdentifierValue(val->id);
3547            default:
3548                break;
3549            }
3550        } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
3551            parsedValue = createPrimitiveStringValue(val);
3552        }
3553        if (!parsedValue)
3554            break;
3555        values->append(parsedValue.release());
3556        m_valueList->next();
3557    }
3558
3559    if (values->length()) {
3560        addProperty(propId, values.release(), important);
3561        m_valueList->next();
3562        return true;
3563    }
3564
3565    return false;
3566}
3567
3568PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args)
3569{
3570    if (args->size() != 1)
3571        return 0;
3572
3573    CSSParserValue* a = args->current();
3574
3575    if (a->unit != CSSPrimitiveValue::CSS_IDENT)
3576        return 0;
3577
3578    String attrName = a->string;
3579    // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
3580    // But HTML attribute names can't have those characters, and we should not
3581    // even parse them inside attr().
3582    if (attrName[0] == '-')
3583        return 0;
3584
3585    if (m_context.isHTMLDocument())
3586        attrName = attrName.lower();
3587
3588    return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
3589}
3590
3591PassRefPtr<CSSValue> CSSParser::parseBackgroundColor()
3592{
3593    CSSValueID id = m_valueList->current()->id;
3594    if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
3595        (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
3596        return cssValuePool().createIdentifierValue(id);
3597    return parseColor();
3598}
3599
3600bool CSSParser::parseFillImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
3601{
3602    if (valueList->current()->id == CSSValueNone) {
3603        value = cssValuePool().createIdentifierValue(CSSValueNone);
3604        return true;
3605    }
3606    if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
3607        value = CSSImageValue::create(completeURL(valueList->current()->string));
3608        return true;
3609    }
3610
3611    if (isGeneratedImageValue(valueList->current()))
3612        return parseGeneratedImage(valueList, value);
3613
3614    if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) {
3615        value = parseImageSet(m_valueList.get());
3616        if (value)
3617            return true;
3618    }
3619
3620    return false;
3621}
3622
3623PassRefPtr<CSSValue> CSSParser::parseFillPositionX(CSSParserValueList* valueList)
3624{
3625    int id = valueList->current()->id;
3626    if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
3627        int percent = 0;
3628        if (id == CSSValueRight)
3629            percent = 100;
3630        else if (id == CSSValueCenter)
3631            percent = 50;
3632        return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3633    }
3634    if (validUnit(valueList->current(), FPercent | FLength))
3635        return createPrimitiveNumericValue(valueList->current());
3636    return 0;
3637}
3638
3639PassRefPtr<CSSValue> CSSParser::parseFillPositionY(CSSParserValueList* valueList)
3640{
3641    int id = valueList->current()->id;
3642    if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
3643        int percent = 0;
3644        if (id == CSSValueBottom)
3645            percent = 100;
3646        else if (id == CSSValueCenter)
3647            percent = 50;
3648        return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3649    }
3650    if (validUnit(valueList->current(), FPercent | FLength))
3651        return createPrimitiveNumericValue(valueList->current());
3652    return 0;
3653}
3654
3655PassRefPtr<CSSPrimitiveValue> CSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode)
3656{
3657    CSSValueID id = valueList->current()->id;
3658    if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
3659        int percent = 0;
3660        if (id == CSSValueLeft || id == CSSValueRight) {
3661            if (cumulativeFlags & XFillPosition)
3662                return 0;
3663            cumulativeFlags |= XFillPosition;
3664            individualFlag = XFillPosition;
3665            if (id == CSSValueRight)
3666                percent = 100;
3667        }
3668        else if (id == CSSValueTop || id == CSSValueBottom) {
3669            if (cumulativeFlags & YFillPosition)
3670                return 0;
3671            cumulativeFlags |= YFillPosition;
3672            individualFlag = YFillPosition;
3673            if (id == CSSValueBottom)
3674                percent = 100;
3675        } else if (id == CSSValueCenter) {
3676            // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
3677            percent = 50;
3678            cumulativeFlags |= AmbiguousFillPosition;
3679            individualFlag = AmbiguousFillPosition;
3680        }
3681
3682        if (parsingMode == ResolveValuesAsKeyword)
3683            return cssValuePool().createIdentifierValue(id);
3684
3685        return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3686    }
3687    if (validUnit(valueList->current(), FPercent | FLength)) {
3688        if (!cumulativeFlags) {
3689            cumulativeFlags |= XFillPosition;
3690            individualFlag = XFillPosition;
3691        } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
3692            cumulativeFlags |= YFillPosition;
3693            individualFlag = YFillPosition;
3694        } else {
3695            if (m_parsedCalculation)
3696                m_parsedCalculation.release();
3697            return 0;
3698        }
3699        return createPrimitiveNumericValue(valueList->current());
3700    }
3701    return 0;
3702}
3703
3704static bool isValueConflictingWithCurrentEdge(int value1, int value2)
3705{
3706    if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSValueLeft || value2 == CSSValueRight))
3707        return true;
3708
3709    if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSValueTop || value2 == CSSValueBottom))
3710        return true;
3711
3712    return false;
3713}
3714
3715static bool isFillPositionKeyword(CSSValueID value)
3716{
3717    return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter;
3718}
3719
3720void CSSParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtr<CSSPrimitiveValue> parsedValue1, PassRefPtr<CSSPrimitiveValue> parsedValue2)
3721{
3722    // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <percentage> | <length> ]
3723    // In the case of 4 values <position> requires the second value to be a length or a percentage.
3724    if (isFillPositionKeyword(parsedValue2->getValueID()))
3725        return;
3726
3727    unsigned cumulativeFlags = 0;
3728    FillPositionFlag value3Flag = InvalidFillPosition;
3729    RefPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
3730    if (!value3)
3731        return;
3732
3733    CSSValueID ident1 = parsedValue1->getValueID();
3734    CSSValueID ident3 = value3->getValueID();
3735
3736    if (ident1 == CSSValueCenter)
3737        return;
3738
3739    if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
3740        return;
3741
3742    // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
3743    // needed as the second call to parseFillPositionComponent was on purpose not checking it. In the
3744    // case of two values top 20px is invalid but in the case of 4 values it becomes valid.
3745    if (isValueConflictingWithCurrentEdge(ident1, ident3))
3746        return;
3747
3748    valueList->next();
3749
3750    cumulativeFlags = 0;
3751    FillPositionFlag value4Flag = InvalidFillPosition;
3752    RefPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(valueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
3753    if (!value4)
3754        return;
3755
3756    // 4th value must be a length or a percentage.
3757    if (isFillPositionKeyword(value4->getValueID()))
3758        return;
3759
3760    value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
3761    value2 = createPrimitiveValuePair(value3, value4);
3762
3763    if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
3764        value1.swap(value2);
3765
3766    valueList->next();
3767}
3768void CSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtr<CSSPrimitiveValue> parsedValue1, PassRefPtr<CSSPrimitiveValue> parsedValue2)
3769{
3770    unsigned cumulativeFlags = 0;
3771    FillPositionFlag value3Flag = InvalidFillPosition;
3772    RefPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
3773
3774    // value3 is not an expected value, we return.
3775    if (!value3)
3776        return;
3777
3778    valueList->next();
3779
3780    bool swapNeeded = false;
3781    CSSValueID ident1 = parsedValue1->getValueID();
3782    CSSValueID ident2 = parsedValue2->getValueID();
3783    CSSValueID ident3 = value3->getValueID();
3784
3785    CSSValueID firstPositionKeyword;
3786    CSSValueID secondPositionKeyword;
3787
3788    if (ident1 == CSSValueCenter) {
3789        // <position> requires the first 'center' to be followed by a keyword.
3790        if (!isFillPositionKeyword(ident2))
3791            return;
3792
3793        // If 'center' is the first keyword then the last one needs to be a length.
3794        if (isFillPositionKeyword(ident3))
3795            return;
3796
3797        firstPositionKeyword = CSSValueLeft;
3798        if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
3799            firstPositionKeyword = CSSValueTop;
3800            swapNeeded = true;
3801        }
3802        value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
3803        value2 = createPrimitiveValuePair(parsedValue2, value3);
3804    } else if (ident3 == CSSValueCenter) {
3805        if (isFillPositionKeyword(ident2))
3806            return;
3807
3808        secondPositionKeyword = CSSValueTop;
3809        if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
3810            secondPositionKeyword = CSSValueLeft;
3811            swapNeeded = true;
3812        }
3813        value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
3814        value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
3815    } else {
3816        RefPtr<CSSPrimitiveValue> firstPositionValue;
3817        RefPtr<CSSPrimitiveValue> secondPositionValue;
3818
3819        if (isFillPositionKeyword(ident2)) {
3820            // To match CSS grammar, we should only accept: [ center | left | right | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ].
3821            ASSERT(ident2 != CSSValueCenter);
3822
3823            if (isFillPositionKeyword(ident3))
3824                return;
3825
3826            secondPositionValue = value3;
3827            secondPositionKeyword = ident2;
3828            firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
3829        } else {
3830            // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
3831            if (!isFillPositionKeyword(ident3))
3832                return;
3833
3834            firstPositionValue = parsedValue2;
3835            secondPositionKeyword = ident3;
3836            secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
3837        }
3838
3839        if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
3840            return;
3841
3842        value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue);
3843        value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue);
3844    }
3845
3846    if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
3847        value1.swap(value2);
3848
3849#ifndef NDEBUG
3850    CSSPrimitiveValue* first = toCSSPrimitiveValue(value1.get());
3851    CSSPrimitiveValue* second = toCSSPrimitiveValue(value2.get());
3852    ident1 = first->getPairValue()->first()->getValueID();
3853    ident2 = second->getPairValue()->first()->getValueID();
3854    ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
3855    ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
3856#endif
3857}
3858
3859inline bool CSSParser::isPotentialPositionValue(CSSParserValue* value)
3860{
3861    return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue);
3862}
3863
3864void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
3865{
3866    unsigned numberOfValues = 0;
3867    for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++numberOfValues) {
3868        CSSParserValue* current = valueList->valueAt(i);
3869        if (isComma(current) || !current || isForwardSlashOperator(current) || !isPotentialPositionValue(current))
3870            break;
3871    }
3872
3873    if (numberOfValues > 4)
3874        return;
3875
3876    // If we are parsing two values, we can safely call the CSS 2.1 parsing function and return.
3877    if (numberOfValues <= 2) {
3878        parse2ValuesFillPosition(valueList, value1, value2);
3879        return;
3880    }
3881
3882    ASSERT(numberOfValues > 2 && numberOfValues <= 4);
3883
3884    CSSParserValue* value = valueList->current();
3885
3886    // <position> requires the first value to be a background keyword.
3887    if (!isFillPositionKeyword(value->id))
3888        return;
3889
3890    // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
3891    unsigned cumulativeFlags = 0;
3892    FillPositionFlag value1Flag = InvalidFillPosition;
3893    FillPositionFlag value2Flag = InvalidFillPosition;
3894    value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
3895    if (!value1)
3896        return;
3897
3898    value = valueList->next();
3899
3900    // In case we are parsing more than two values, relax the check inside of parseFillPositionComponent. top 20px is
3901    // a valid start for <position>.
3902    cumulativeFlags = AmbiguousFillPosition;
3903    value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
3904    if (value2)
3905        valueList->next();
3906    else {
3907        value1.clear();
3908        return;
3909    }
3910
3911    RefPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(value1.get());
3912    RefPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(value2.get());
3913
3914    value1.clear();
3915    value2.clear();
3916
3917    // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
3918    if (parsedValue2->getValueID() == CSSValueCenter)
3919        return;
3920
3921    if (numberOfValues == 3)
3922        parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
3923    else
3924        parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
3925}
3926
3927void CSSParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
3928{
3929    CSSParserValue* value = valueList->current();
3930
3931    // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
3932    unsigned cumulativeFlags = 0;
3933    FillPositionFlag value1Flag = InvalidFillPosition;
3934    FillPositionFlag value2Flag = InvalidFillPosition;
3935    value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
3936    if (!value1)
3937        return;
3938
3939    // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
3940    // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
3941    // value was explicitly specified for our property.
3942    value = valueList->next();
3943
3944    // First check for the comma.  If so, we are finished parsing this value or value pair.
3945    if (isComma(value))
3946        value = 0;
3947
3948    if (value) {
3949        value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
3950        if (value2)
3951            valueList->next();
3952        else {
3953            if (!inShorthand()) {
3954                value1.clear();
3955                return;
3956            }
3957        }
3958    }
3959
3960    if (!value2)
3961        // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
3962        // is simply 50%. This is our default.
3963        // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
3964        // For left/right/center, the default of 50% in the y is still correct.
3965        value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
3966
3967    if (value1Flag == YFillPosition || value2Flag == XFillPosition)
3968        value1.swap(value2);
3969}
3970
3971void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
3972{
3973    CSSValueID id = m_valueList->current()->id;
3974    if (id == CSSValueRepeatX) {
3975        m_implicitShorthand = true;
3976        value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
3977        value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
3978        m_valueList->next();
3979        return;
3980    }
3981    if (id == CSSValueRepeatY) {
3982        m_implicitShorthand = true;
3983        value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
3984        value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
3985        m_valueList->next();
3986        return;
3987    }
3988    if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
3989        value1 = cssValuePool().createIdentifierValue(id);
3990    else {
3991        value1 = 0;
3992        return;
3993    }
3994
3995    CSSParserValue* value = m_valueList->next();
3996
3997    // Parse the second value if one is available
3998    if (value && !isComma(value)) {
3999        id = value->id;
4000        if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
4001            value2 = cssValuePool().createIdentifierValue(id);
4002            m_valueList->next();
4003            return;
4004        }
4005    }
4006
4007    // If only one value was specified, value2 is the same as value1.
4008    m_implicitShorthand = true;
4009    value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get())->getValueID());
4010}
4011
4012PassRefPtr<CSSValue> CSSParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
4013{
4014    allowComma = true;
4015    CSSParserValue* value = m_valueList->current();
4016
4017    if (value->id == CSSValueContain || value->id == CSSValueCover)
4018        return cssValuePool().createIdentifierValue(value->id);
4019
4020    RefPtr<CSSPrimitiveValue> parsedValue1;
4021
4022    if (value->id == CSSValueAuto)
4023        parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
4024    else {
4025        if (!validUnit(value, FLength | FPercent))
4026            return 0;
4027        parsedValue1 = createPrimitiveNumericValue(value);
4028    }
4029
4030    RefPtr<CSSPrimitiveValue> parsedValue2;
4031    if ((value = m_valueList->next())) {
4032        if (value->unit == CSSParserValue::Operator && value->iValue == ',')
4033            allowComma = false;
4034        else if (value->id != CSSValueAuto) {
4035            if (!validUnit(value, FLength | FPercent)) {
4036                if (!inShorthand())
4037                    return 0;
4038                // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
4039                m_valueList->previous();
4040            } else
4041                parsedValue2 = createPrimitiveNumericValue(value);
4042        }
4043    } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
4044        // For backwards compatibility we set the second value to the first if it is omitted.
4045        // We only need to do this for -webkit-background-size. It should be safe to let masks match
4046        // the real property.
4047        parsedValue2 = parsedValue1;
4048    }
4049
4050    if (!parsedValue2)
4051        return parsedValue1;
4052    return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release());
4053}
4054
4055bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
4056                                  RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
4057{
4058    RefPtr<CSSValueList> values;
4059    RefPtr<CSSValueList> values2;
4060    CSSParserValue* val;
4061    RefPtr<CSSValue> value;
4062    RefPtr<CSSValue> value2;
4063
4064    bool allowComma = false;
4065
4066    retValue1 = retValue2 = 0;
4067    propId1 = propId;
4068    propId2 = propId;
4069    if (propId == CSSPropertyBackgroundPosition) {
4070        propId1 = CSSPropertyBackgroundPositionX;
4071        propId2 = CSSPropertyBackgroundPositionY;
4072    } else if (propId == CSSPropertyWebkitMaskPosition) {
4073        propId1 = CSSPropertyWebkitMaskPositionX;
4074        propId2 = CSSPropertyWebkitMaskPositionY;
4075    } else if (propId == CSSPropertyBackgroundRepeat) {
4076        propId1 = CSSPropertyBackgroundRepeatX;
4077        propId2 = CSSPropertyBackgroundRepeatY;
4078    } else if (propId == CSSPropertyWebkitMaskRepeat) {
4079        propId1 = CSSPropertyWebkitMaskRepeatX;
4080        propId2 = CSSPropertyWebkitMaskRepeatY;
4081    }
4082
4083    while ((val = m_valueList->current())) {
4084        RefPtr<CSSValue> currValue;
4085        RefPtr<CSSValue> currValue2;
4086
4087        if (allowComma) {
4088            if (!isComma(val))
4089                return false;
4090            m_valueList->next();
4091            allowComma = false;
4092        } else {
4093            allowComma = true;
4094            switch (propId) {
4095                case CSSPropertyBackgroundColor:
4096                    currValue = parseBackgroundColor();
4097                    if (currValue)
4098                        m_valueList->next();
4099                    break;
4100                case CSSPropertyBackgroundAttachment:
4101                    if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
4102                        currValue = cssValuePool().createIdentifierValue(val->id);
4103                        m_valueList->next();
4104                    }
4105                    break;
4106                case CSSPropertyBackgroundImage:
4107                case CSSPropertyWebkitMaskImage:
4108                    if (parseFillImage(m_valueList.get(), currValue))
4109                        m_valueList->next();
4110                    break;
4111                case CSSPropertyWebkitBackgroundClip:
4112                case CSSPropertyWebkitBackgroundOrigin:
4113                case CSSPropertyWebkitMaskClip:
4114                case CSSPropertyWebkitMaskOrigin:
4115                    // The first three values here are deprecated and do not apply to the version of the property that has
4116                    // the -webkit- prefix removed.
4117                    if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
4118                        val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
4119                        ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
4120                         (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
4121                        currValue = cssValuePool().createIdentifierValue(val->id);
4122                        m_valueList->next();
4123                    }
4124                    break;
4125                case CSSPropertyBackgroundClip:
4126                    if (parseBackgroundClip(val, currValue))
4127                        m_valueList->next();
4128                    break;
4129                case CSSPropertyBackgroundOrigin:
4130                    if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
4131                        currValue = cssValuePool().createIdentifierValue(val->id);
4132                        m_valueList->next();
4133                    }
4134                    break;
4135                case CSSPropertyBackgroundPosition:
4136                case CSSPropertyWebkitMaskPosition:
4137                    parseFillPosition(m_valueList.get(), currValue, currValue2);
4138                    // parseFillPosition advances the m_valueList pointer.
4139                    break;
4140                case CSSPropertyBackgroundPositionX:
4141                case CSSPropertyWebkitMaskPositionX: {
4142                    currValue = parseFillPositionX(m_valueList.get());
4143                    if (currValue)
4144                        m_valueList->next();
4145                    break;
4146                }
4147                case CSSPropertyBackgroundPositionY:
4148                case CSSPropertyWebkitMaskPositionY: {
4149                    currValue = parseFillPositionY(m_valueList.get());
4150                    if (currValue)
4151                        m_valueList->next();
4152                    break;
4153                }
4154                case CSSPropertyWebkitBackgroundComposite:
4155                case CSSPropertyWebkitMaskComposite:
4156                    if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) {
4157                        currValue = cssValuePool().createIdentifierValue(val->id);
4158                        m_valueList->next();
4159                    }
4160                    break;
4161                case CSSPropertyBackgroundBlendMode:
4162                    if (RuntimeEnabledFeatures::cssCompositingEnabled() && (val->id == CSSValueNormal || val->id == CSSValueMultiply
4163                        || val->id == CSSValueScreen || val->id == CSSValueOverlay || val->id == CSSValueDarken
4164                        || val->id == CSSValueLighten ||  val->id == CSSValueColorDodge || val->id == CSSValueColorBurn
4165                        || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference
4166                        || val->id == CSSValueExclusion || val->id == CSSValueHue || val->id == CSSValueSaturation
4167                        || val->id == CSSValueColor || val->id == CSSValueLuminosity)) {
4168                        currValue = cssValuePool().createIdentifierValue(val->id);
4169                        m_valueList->next();
4170                    }
4171                    break;
4172                case CSSPropertyBackgroundRepeat:
4173                case CSSPropertyWebkitMaskRepeat:
4174                    parseFillRepeat(currValue, currValue2);
4175                    // parseFillRepeat advances the m_valueList pointer
4176                    break;
4177                case CSSPropertyBackgroundSize:
4178                case CSSPropertyWebkitBackgroundSize:
4179                case CSSPropertyWebkitMaskSize: {
4180                    currValue = parseFillSize(propId, allowComma);
4181                    if (currValue)
4182                        m_valueList->next();
4183                    break;
4184                }
4185                case CSSPropertyMaskSourceType: {
4186                    if (RuntimeEnabledFeatures::cssMaskSourceTypeEnabled()) {
4187                        if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id == CSSValueLuminance) {
4188                            currValue = cssValuePool().createIdentifierValue(val->id);
4189                            m_valueList->next();
4190                        } else {
4191                            currValue = 0;
4192                        }
4193                    }
4194                    break;
4195                }
4196                default:
4197                    break;
4198            }
4199            if (!currValue)
4200                return false;
4201
4202            if (value && !values) {
4203                values = CSSValueList::createCommaSeparated();
4204                values->append(value.release());
4205            }
4206
4207            if (value2 && !values2) {
4208                values2 = CSSValueList::createCommaSeparated();
4209                values2->append(value2.release());
4210            }
4211
4212            if (values)
4213                values->append(currValue.release());
4214            else
4215                value = currValue.release();
4216            if (currValue2) {
4217                if (values2)
4218                    values2->append(currValue2.release());
4219                else
4220                    value2 = currValue2.release();
4221            }
4222        }
4223
4224        // When parsing any fill shorthand property, we let it handle building up the lists for all
4225        // properties.
4226        if (inShorthand())
4227            break;
4228    }
4229
4230    if (values && values->length()) {
4231        retValue1 = values.release();
4232        if (values2 && values2->length())
4233            retValue2 = values2.release();
4234        return true;
4235    }
4236    if (value) {
4237        retValue1 = value.release();
4238        retValue2 = value2.release();
4239        return true;
4240    }
4241    return false;
4242}
4243
4244PassRefPtr<CSSValue> CSSParser::parseAnimationDelay()
4245{
4246    CSSParserValue* value = m_valueList->current();
4247    if (validUnit(value, FTime))
4248        return createPrimitiveNumericValue(value);
4249    return 0;
4250}
4251
4252PassRefPtr<CSSValue> CSSParser::parseAnimationDirection()
4253{
4254    CSSParserValue* value = m_valueList->current();
4255    if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
4256        return cssValuePool().createIdentifierValue(value->id);
4257    return 0;
4258}
4259
4260PassRefPtr<CSSValue> CSSParser::parseAnimationDuration()
4261{
4262    CSSParserValue* value = m_valueList->current();
4263    if (validUnit(value, FTime | FNonNeg))
4264        return createPrimitiveNumericValue(value);
4265    return 0;
4266}
4267
4268PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode()
4269{
4270    CSSParserValue* value = m_valueList->current();
4271    if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
4272        return cssValuePool().createIdentifierValue(value->id);
4273    return 0;
4274}
4275
4276PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount()
4277{
4278    CSSParserValue* value = m_valueList->current();
4279    if (value->id == CSSValueInfinite)
4280        return cssValuePool().createIdentifierValue(value->id);
4281    if (validUnit(value, FNumber | FNonNeg))
4282        return createPrimitiveNumericValue(value);
4283    return 0;
4284}
4285
4286PassRefPtr<CSSValue> CSSParser::parseAnimationName()
4287{
4288    CSSParserValue* value = m_valueList->current();
4289    if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
4290        if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value, "none"))) {
4291            return cssValuePool().createIdentifierValue(CSSValueNone);
4292        } else {
4293            return createPrimitiveStringValue(value);
4294        }
4295    }
4296    return 0;
4297}
4298
4299PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState()
4300{
4301    CSSParserValue* value = m_valueList->current();
4302    if (value->id == CSSValueRunning || value->id == CSSValuePaused)
4303        return cssValuePool().createIdentifierValue(value->id);
4304    return 0;
4305}
4306
4307PassRefPtr<CSSValue> CSSParser::parseAnimationProperty(AnimationParseContext& context)
4308{
4309    CSSParserValue* value = m_valueList->current();
4310    if (value->unit != CSSPrimitiveValue::CSS_IDENT)
4311        return 0;
4312    CSSPropertyID result = cssPropertyID(value->string);
4313    if (result)
4314        return cssValuePool().createIdentifierValue(result);
4315    if (equalIgnoringCase(value, "all")) {
4316        context.sawAnimationPropertyKeyword();
4317        return cssValuePool().createIdentifierValue(CSSValueAll);
4318    }
4319    if (equalIgnoringCase(value, "none")) {
4320        context.commitAnimationPropertyKeyword();
4321        context.sawAnimationPropertyKeyword();
4322        return cssValuePool().createIdentifierValue(CSSValueNone);
4323    }
4324    return 0;
4325}
4326
4327bool CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
4328{
4329    parse2ValuesFillPosition(m_valueList.get(), value1, value2);
4330
4331    // now get z
4332    if (m_valueList->current()) {
4333        if (validUnit(m_valueList->current(), FLength)) {
4334            value3 = createPrimitiveNumericValue(m_valueList->current());
4335            m_valueList->next();
4336            return true;
4337        }
4338        return false;
4339    }
4340    value3 = cssValuePool().createImplicitInitialValue();
4341    return true;
4342}
4343
4344bool CSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
4345{
4346    CSSParserValue* v = args->current();
4347    if (!validUnit(v, FNumber))
4348        return false;
4349    result = v->fValue;
4350    v = args->next();
4351    if (!v)
4352        // The last number in the function has no comma after it, so we're done.
4353        return true;
4354    if (!isComma(v))
4355        return false;
4356    args->next();
4357    return true;
4358}
4359
4360PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction()
4361{
4362    CSSParserValue* value = m_valueList->current();
4363    if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
4364        || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd)
4365        return cssValuePool().createIdentifierValue(value->id);
4366
4367    // We must be a function.
4368    if (value->unit != CSSParserValue::Function)
4369        return 0;
4370
4371    CSSParserValueList* args = value->function->args.get();
4372
4373    if (equalIgnoringCase(value->function->name, "steps(")) {
4374        // For steps, 1 or 2 params must be specified (comma-separated)
4375        if (!args || (args->size() != 1 && args->size() != 3))
4376            return 0;
4377
4378        // There are two values.
4379        int numSteps;
4380        bool stepAtStart = false;
4381
4382        CSSParserValue* v = args->current();
4383        if (!validUnit(v, FInteger))
4384            return 0;
4385        numSteps = clampToInteger(v->fValue);
4386        if (numSteps < 1)
4387            return 0;
4388        v = args->next();
4389
4390        if (v) {
4391            // There is a comma so we need to parse the second value
4392            if (!isComma(v))
4393                return 0;
4394            v = args->next();
4395            if (v->id != CSSValueStart && v->id != CSSValueEnd)
4396                return 0;
4397            stepAtStart = v->id == CSSValueStart;
4398        }
4399
4400        return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart);
4401    }
4402
4403    if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
4404        // For cubic bezier, 4 values must be specified.
4405        if (!args || args->size() != 7)
4406            return 0;
4407
4408        // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range.
4409        double x1, y1, x2, y2;
4410
4411        if (!parseCubicBezierTimingFunctionValue(args, x1))
4412            return 0;
4413        if (x1 < 0 || x1 > 1)
4414            return 0;
4415        if (!parseCubicBezierTimingFunctionValue(args, y1))
4416            return 0;
4417        if (!parseCubicBezierTimingFunctionValue(args, x2))
4418            return 0;
4419        if (x2 < 0 || x2 > 1)
4420            return 0;
4421        if (!parseCubicBezierTimingFunctionValue(args, y2))
4422            return 0;
4423
4424        return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
4425    }
4426
4427    return 0;
4428}
4429
4430bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& result, AnimationParseContext& context)
4431{
4432    RefPtr<CSSValueList> values;
4433    CSSParserValue* val;
4434    RefPtr<CSSValue> value;
4435    bool allowComma = false;
4436
4437    result = 0;
4438
4439    while ((val = m_valueList->current())) {
4440        RefPtr<CSSValue> currValue;
4441        if (allowComma) {
4442            if (!isComma(val))
4443                return false;
4444            m_valueList->next();
4445            allowComma = false;
4446        }
4447        else {
4448            switch (propId) {
4449                case CSSPropertyAnimationDelay:
4450                case CSSPropertyWebkitAnimationDelay:
4451                case CSSPropertyTransitionDelay:
4452                case CSSPropertyWebkitTransitionDelay:
4453                    currValue = parseAnimationDelay();
4454                    if (currValue)
4455                        m_valueList->next();
4456                    break;
4457                case CSSPropertyAnimationDirection:
4458                case CSSPropertyWebkitAnimationDirection:
4459                    currValue = parseAnimationDirection();
4460                    if (currValue)
4461                        m_valueList->next();
4462                    break;
4463                case CSSPropertyAnimationDuration:
4464                case CSSPropertyWebkitAnimationDuration:
4465                case CSSPropertyTransitionDuration:
4466                case CSSPropertyWebkitTransitionDuration:
4467                    currValue = parseAnimationDuration();
4468                    if (currValue)
4469                        m_valueList->next();
4470                    break;
4471                case CSSPropertyAnimationFillMode:
4472                case CSSPropertyWebkitAnimationFillMode:
4473                    currValue = parseAnimationFillMode();
4474                    if (currValue)
4475                        m_valueList->next();
4476                    break;
4477                case CSSPropertyAnimationIterationCount:
4478                case CSSPropertyWebkitAnimationIterationCount:
4479                    currValue = parseAnimationIterationCount();
4480                    if (currValue)
4481                        m_valueList->next();
4482                    break;
4483                case CSSPropertyAnimationName:
4484                case CSSPropertyWebkitAnimationName:
4485                    currValue = parseAnimationName();
4486                    if (currValue)
4487                        m_valueList->next();
4488                    break;
4489                case CSSPropertyAnimationPlayState:
4490                case CSSPropertyWebkitAnimationPlayState:
4491                    currValue = parseAnimationPlayState();
4492                    if (currValue)
4493                        m_valueList->next();
4494                    break;
4495                case CSSPropertyTransitionProperty:
4496                case CSSPropertyWebkitTransitionProperty:
4497                    currValue = parseAnimationProperty(context);
4498                    if (value && !context.animationPropertyKeywordAllowed())
4499                        return false;
4500                    if (currValue)
4501                        m_valueList->next();
4502                    break;
4503                case CSSPropertyAnimationTimingFunction:
4504                case CSSPropertyWebkitAnimationTimingFunction:
4505                case CSSPropertyTransitionTimingFunction:
4506                case CSSPropertyWebkitTransitionTimingFunction:
4507                    currValue = parseAnimationTimingFunction();
4508                    if (currValue)
4509                        m_valueList->next();
4510                    break;
4511                default:
4512                    ASSERT_NOT_REACHED();
4513                    return false;
4514            }
4515
4516            if (!currValue)
4517                return false;
4518
4519            if (value && !values) {
4520                values = CSSValueList::createCommaSeparated();
4521                values->append(value.release());
4522            }
4523
4524            if (values)
4525                values->append(currValue.release());
4526            else
4527                value = currValue.release();
4528
4529            allowComma = true;
4530        }
4531
4532        // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
4533        // properties.
4534        if (inShorthand())
4535            break;
4536    }
4537
4538    if (values && values->length()) {
4539        result = values.release();
4540        return true;
4541    }
4542    if (value) {
4543        result = value.release();
4544        return true;
4545    }
4546    return false;
4547}
4548
4549// The function parses [ <integer> || <string> ] in <grid-line> (which can be stand alone or with 'span').
4550bool CSSParser::parseIntegerOrStringFromGridPosition(RefPtr<CSSPrimitiveValue>& numericValue, RefPtr<CSSPrimitiveValue>& gridLineName)
4551{
4552    CSSParserValue* value = m_valueList->current();
4553    if (validUnit(value, FInteger) && value->fValue) {
4554        numericValue = createPrimitiveNumericValue(value);
4555        value = m_valueList->next();
4556        if (value && value->unit == CSSPrimitiveValue::CSS_STRING) {
4557            gridLineName = createPrimitiveStringValue(m_valueList->current());
4558            m_valueList->next();
4559        }
4560        return true;
4561    }
4562
4563    if (value->unit == CSSPrimitiveValue::CSS_STRING) {
4564        gridLineName = createPrimitiveStringValue(m_valueList->current());
4565        value = m_valueList->next();
4566        if (value && validUnit(value, FInteger) && value->fValue) {
4567            numericValue = createPrimitiveNumericValue(value);
4568            m_valueList->next();
4569        }
4570        return true;
4571    }
4572
4573    return false;
4574}
4575
4576PassRefPtr<CSSValue> CSSParser::parseGridPosition()
4577{
4578    ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4579
4580    CSSParserValue* value = m_valueList->current();
4581    if (value->id == CSSValueAuto) {
4582        m_valueList->next();
4583        return cssValuePool().createIdentifierValue(CSSValueAuto);
4584    }
4585
4586    if (value->id != CSSValueSpan && value->unit == CSSPrimitiveValue::CSS_IDENT) {
4587        m_valueList->next();
4588        return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
4589    }
4590
4591    RefPtr<CSSPrimitiveValue> numericValue;
4592    RefPtr<CSSPrimitiveValue> gridLineName;
4593    bool hasSeenSpanKeyword = false;
4594
4595    if (parseIntegerOrStringFromGridPosition(numericValue, gridLineName)) {
4596        value = m_valueList->current();
4597        if (value && value->id == CSSValueSpan) {
4598            hasSeenSpanKeyword = true;
4599            m_valueList->next();
4600        }
4601    } else if (value->id == CSSValueSpan) {
4602        hasSeenSpanKeyword = true;
4603        if (m_valueList->next())
4604            parseIntegerOrStringFromGridPosition(numericValue, gridLineName);
4605    }
4606
4607    // Check that we have consumed all the value list. For shorthands, the parser will pass
4608    // the whole value list (including the opposite position).
4609    if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current()))
4610        return 0;
4611
4612    // If we didn't parse anything, this is not a valid grid position.
4613    if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
4614        return 0;
4615
4616    // Negative numbers are not allowed for span (but are for <integer>).
4617    if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
4618        return 0;
4619
4620    RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
4621    if (hasSeenSpanKeyword)
4622        values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
4623    if (numericValue)
4624        values->append(numericValue.release());
4625    if (gridLineName)
4626        values->append(gridLineName.release());
4627    ASSERT(values->length());
4628    return values.release();
4629}
4630
4631static PassRefPtr<CSSValue> gridMissingGridPositionValue(CSSValue* value)
4632{
4633    if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isString())
4634        return value;
4635
4636    return cssValuePool().createIdentifierValue(CSSValueAuto);
4637}
4638
4639bool CSSParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
4640{
4641    ShorthandScope scope(this, shorthandId);
4642    const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
4643    ASSERT(shorthand.length() == 2);
4644
4645    RefPtr<CSSValue> startValue = parseGridPosition();
4646    if (!startValue)
4647        return false;
4648
4649    RefPtr<CSSValue> endValue;
4650    if (m_valueList->current()) {
4651        if (!isForwardSlashOperator(m_valueList->current()))
4652            return false;
4653
4654        if (!m_valueList->next())
4655            return false;
4656
4657        endValue = parseGridPosition();
4658        if (!endValue || m_valueList->current())
4659            return false;
4660    } else {
4661        endValue = gridMissingGridPositionValue(startValue.get());
4662    }
4663
4664    addProperty(shorthand.properties()[0], startValue, important);
4665    addProperty(shorthand.properties()[1], endValue, important);
4666    return true;
4667}
4668
4669bool CSSParser::parseGridAreaShorthand(bool important)
4670{
4671    ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4672
4673    ShorthandScope scope(this, CSSPropertyGridArea);
4674    const StylePropertyShorthand& shorthand = gridAreaShorthand();
4675    ASSERT_UNUSED(shorthand, shorthand.length() == 4);
4676
4677    RefPtr<CSSValue> rowStartValue = parseGridPosition();
4678    if (!rowStartValue)
4679        return false;
4680
4681    RefPtr<CSSValue> columnStartValue;
4682    if (!parseSingleGridAreaLonghand(columnStartValue))
4683        return false;
4684
4685    RefPtr<CSSValue> rowEndValue;
4686    if (!parseSingleGridAreaLonghand(rowEndValue))
4687        return false;
4688
4689    RefPtr<CSSValue> columnEndValue;
4690    if (!parseSingleGridAreaLonghand(columnEndValue))
4691        return false;
4692
4693    if (!columnStartValue)
4694        columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
4695
4696    if (!rowEndValue)
4697        rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
4698
4699    if (!columnEndValue)
4700        columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
4701
4702    addProperty(CSSPropertyGridRowStart, rowStartValue, important);
4703    addProperty(CSSPropertyGridColumnStart, columnStartValue, important);
4704    addProperty(CSSPropertyGridRowEnd, rowEndValue, important);
4705    addProperty(CSSPropertyGridColumnEnd, columnEndValue, important);
4706    return true;
4707}
4708
4709bool CSSParser::parseSingleGridAreaLonghand(RefPtr<CSSValue>& property)
4710{
4711    if (!m_valueList->current())
4712        return true;
4713
4714    if (!isForwardSlashOperator(m_valueList->current()))
4715        return false;
4716
4717    if (!m_valueList->next())
4718        return false;
4719
4720    property = parseGridPosition();
4721    return true;
4722}
4723
4724void CSSParser::parseGridLineNames(CSSParserValueList* parserValueList, CSSValueList& valueList)
4725{
4726    ASSERT(parserValueList->current() && parserValueList->current()->unit == CSSParserValue::ValueList);
4727
4728    CSSParserValueList* identList = parserValueList->current()->valueList;
4729    if (!identList->size()) {
4730        parserValueList->next();
4731        return;
4732    }
4733
4734    RefPtr<CSSGridLineNamesValue> lineNames = CSSGridLineNamesValue::create();
4735    while (CSSParserValue* identValue = identList->current()) {
4736        ASSERT(identValue->unit == CSSPrimitiveValue::CSS_IDENT);
4737        RefPtr<CSSPrimitiveValue> lineName = createPrimitiveStringValue(identValue);
4738        lineNames->append(lineName.release());
4739        identList->next();
4740    }
4741    valueList.append(lineNames.release());
4742
4743    parserValueList->next();
4744}
4745
4746bool CSSParser::parseGridTrackList(CSSPropertyID propId, bool important)
4747{
4748    ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4749
4750    CSSParserValue* value = m_valueList->current();
4751    if (value->id == CSSValueNone) {
4752        if (m_valueList->next())
4753            return false;
4754
4755        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
4756        return true;
4757    }
4758
4759    RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
4760    // Handle leading  <ident>*.
4761    value = m_valueList->current();
4762    if (value && value->unit == CSSParserValue::ValueList)
4763        parseGridLineNames(m_valueList.get(), *values);
4764
4765    bool seenTrackSizeOrRepeatFunction = false;
4766    while (CSSParserValue* currentValue = m_valueList->current()) {
4767        if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "repeat(")) {
4768            if (!parseGridTrackRepeatFunction(*values))
4769                return false;
4770            seenTrackSizeOrRepeatFunction = true;
4771        } else {
4772            RefPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
4773            if (!value)
4774                return false;
4775            values->append(value);
4776            seenTrackSizeOrRepeatFunction = true;
4777        }
4778        // This will handle the trailing <ident>* in the grammar.
4779        value = m_valueList->current();
4780        if (value && value->unit == CSSParserValue::ValueList)
4781            parseGridLineNames(m_valueList.get(), *values);
4782    }
4783
4784    // We should have found a <track-size> or else it is not a valid <track-list>
4785    if (!seenTrackSizeOrRepeatFunction)
4786        return false;
4787
4788    addProperty(propId, values.release(), important);
4789    return true;
4790}
4791
4792bool CSSParser::parseGridTrackRepeatFunction(CSSValueList& list)
4793{
4794    CSSParserValueList* arguments = m_valueList->current()->function->args.get();
4795    if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1)))
4796        return false;
4797
4798    ASSERT_WITH_SECURITY_IMPLICATION(arguments->valueAt(0)->fValue > 0);
4799    size_t repetitions = arguments->valueAt(0)->fValue;
4800    RefPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
4801    arguments->next(); // Skip the repetition count.
4802    arguments->next(); // Skip the comma.
4803
4804    // Handle leading <ident>*.
4805    CSSParserValue* currentValue = arguments->current();
4806    if (currentValue && currentValue->unit == CSSParserValue::ValueList)
4807        parseGridLineNames(arguments, *repeatedValues);
4808
4809    while (arguments->current()) {
4810        RefPtr<CSSValue> trackSize = parseGridTrackSize(*arguments);
4811        if (!trackSize)
4812            return false;
4813
4814        repeatedValues->append(trackSize);
4815
4816        // This takes care of any trailing <ident>* in the grammar.
4817        currentValue = arguments->current();
4818        if (currentValue && currentValue->unit == CSSParserValue::ValueList)
4819            parseGridLineNames(arguments, *repeatedValues);
4820    }
4821
4822    for (size_t i = 0; i < repetitions; ++i) {
4823        for (size_t j = 0; j < repeatedValues->length(); ++j)
4824            list.append(repeatedValues->itemWithoutBoundsCheck(j));
4825    }
4826
4827    // parseGridTrackSize iterated over the repeat arguments, move to the next value.
4828    m_valueList->next();
4829    return true;
4830}
4831
4832PassRefPtr<CSSValue> CSSParser::parseGridTrackSize(CSSParserValueList& inputList)
4833{
4834    ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4835
4836    CSSParserValue* currentValue = inputList.current();
4837    inputList.next();
4838
4839    if (currentValue->id == CSSValueAuto)
4840        return cssValuePool().createIdentifierValue(CSSValueAuto);
4841
4842    if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax(")) {
4843        // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
4844        CSSParserValueList* arguments = currentValue->function->args.get();
4845        if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
4846            return 0;
4847
4848        RefPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0));
4849        if (!minTrackBreadth)
4850            return 0;
4851
4852        RefPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2));
4853        if (!maxTrackBreadth)
4854            return 0;
4855
4856        RefPtr<CSSValueList> parsedArguments = CSSValueList::createCommaSeparated();
4857        parsedArguments->append(minTrackBreadth);
4858        parsedArguments->append(maxTrackBreadth);
4859        return CSSFunctionValue::create("minmax(", parsedArguments);
4860    }
4861
4862    return parseGridBreadth(currentValue);
4863}
4864
4865PassRefPtr<CSSPrimitiveValue> CSSParser::parseGridBreadth(CSSParserValue* currentValue)
4866{
4867    if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMaxContent)
4868        return cssValuePool().createIdentifierValue(currentValue->id);
4869
4870    if (currentValue->unit == CSSPrimitiveValue::CSS_FR) {
4871        double flexValue = currentValue->fValue;
4872
4873        // Fractional unit is a non-negative dimension.
4874        if (flexValue <= 0)
4875            return 0;
4876
4877        return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR);
4878    }
4879
4880    if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
4881        return 0;
4882
4883    return createPrimitiveNumericValue(currentValue);
4884}
4885
4886PassRefPtr<CSSValue> CSSParser::parseGridTemplate()
4887{
4888    NamedGridAreaMap gridAreaMap;
4889    size_t rowCount = 0;
4890    size_t columnCount = 0;
4891
4892    while (CSSParserValue* currentValue = m_valueList->current()) {
4893        if (currentValue->unit != CSSPrimitiveValue::CSS_STRING)
4894            return 0;
4895
4896        String gridRowNames = currentValue->string;
4897        if (!gridRowNames.length())
4898            return 0;
4899
4900        Vector<String> columnNames;
4901        gridRowNames.split(' ', columnNames);
4902
4903        if (!columnCount) {
4904            columnCount = columnNames.size();
4905            ASSERT(columnCount);
4906        } else if (columnCount != columnNames.size()) {
4907            // The declaration is invalid is all the rows don't have the number of columns.
4908            return 0;
4909        }
4910
4911        for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
4912            const String& gridAreaName = columnNames[currentCol];
4913
4914            // Unamed areas are always valid (we consider them to be 1x1).
4915            if (gridAreaName == ".")
4916                continue;
4917
4918            // We handle several grid areas with the same name at once to simplify the validation code.
4919            size_t lookAheadCol;
4920            for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++lookAheadCol) {
4921                if (columnNames[lookAheadCol + 1] != gridAreaName)
4922                    break;
4923            }
4924
4925            NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
4926            if (gridAreaIt == gridAreaMap.end()) {
4927                gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowCount), GridSpan(currentCol, lookAheadCol)));
4928            } else {
4929                GridCoordinate& gridCoordinate = gridAreaIt->value;
4930
4931                // The following checks test that the grid area is a single filled-in rectangle.
4932                // 1. The new row is adjacent to the previously parsed row.
4933                if (rowCount != gridCoordinate.rows.initialPositionIndex + 1)
4934                    return 0;
4935
4936                // 2. The new area starts at the same position as the previously parsed area.
4937                if (currentCol != gridCoordinate.columns.initialPositionIndex)
4938                    return 0;
4939
4940                // 3. The new area ends at the same position as the previously parsed area.
4941                if (lookAheadCol != gridCoordinate.columns.finalPositionIndex)
4942                    return 0;
4943
4944                ++gridCoordinate.rows.finalPositionIndex;
4945            }
4946            currentCol = lookAheadCol;
4947        }
4948
4949        ++rowCount;
4950        m_valueList->next();
4951    }
4952
4953    if (!rowCount || !columnCount)
4954        return 0;
4955
4956    return CSSGridTemplateValue::create(gridAreaMap, rowCount, columnCount);
4957}
4958
4959PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
4960{
4961    unsigned numArgs = args->size();
4962    if (counters && numArgs != 3 && numArgs != 5)
4963        return 0;
4964    if (!counters && numArgs != 1 && numArgs != 3)
4965        return 0;
4966
4967    CSSParserValue* i = args->current();
4968    if (i->unit != CSSPrimitiveValue::CSS_IDENT)
4969        return 0;
4970    RefPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i);
4971
4972    RefPtr<CSSPrimitiveValue> separator;
4973    if (!counters)
4974        separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING);
4975    else {
4976        i = args->next();
4977        if (i->unit != CSSParserValue::Operator || i->iValue != ',')
4978            return 0;
4979
4980        i = args->next();
4981        if (i->unit != CSSPrimitiveValue::CSS_STRING)
4982            return 0;
4983
4984        separator = createPrimitiveStringValue(i);
4985    }
4986
4987    RefPtr<CSSPrimitiveValue> listStyle;
4988    i = args->next();
4989    if (!i) // Make the list style default decimal
4990        listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
4991    else {
4992        if (i->unit != CSSParserValue::Operator || i->iValue != ',')
4993            return 0;
4994
4995        i = args->next();
4996        if (i->unit != CSSPrimitiveValue::CSS_IDENT)
4997            return 0;
4998
4999        CSSValueID listStyleID = CSSValueInvalid;
5000        if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha))
5001            listStyleID = i->id;
5002        else
5003            return 0;
5004
5005        listStyle = cssValuePool().createIdentifierValue(listStyleID);
5006    }
5007
5008    return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
5009}
5010
5011bool CSSParser::parseClipShape(CSSPropertyID propId, bool important)
5012{
5013    CSSParserValue* value = m_valueList->current();
5014    CSSParserValueList* args = value->function->args.get();
5015
5016    if (!equalIgnoringCase(value->function->name, "rect(") || !args)
5017        return false;
5018
5019    // rect(t, r, b, l) || rect(t r b l)
5020    if (args->size() != 4 && args->size() != 7)
5021        return false;
5022    RefPtr<Rect> rect = Rect::create();
5023    bool valid = true;
5024    int i = 0;
5025    CSSParserValue* a = args->current();
5026    while (a) {
5027        valid = a->id == CSSValueAuto || validUnit(a, FLength);
5028        if (!valid)
5029            break;
5030        RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
5031            cssValuePool().createIdentifierValue(CSSValueAuto) :
5032            createPrimitiveNumericValue(a);
5033        if (i == 0)
5034            rect->setTop(length);
5035        else if (i == 1)
5036            rect->setRight(length);
5037        else if (i == 2)
5038            rect->setBottom(length);
5039        else
5040            rect->setLeft(length);
5041        a = args->next();
5042        if (a && args->size() == 7) {
5043            if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
5044                a = args->next();
5045            } else {
5046                valid = false;
5047                break;
5048            }
5049        }
5050        i++;
5051    }
5052    if (valid) {
5053        addProperty(propId, cssValuePool().createValue(rect.release()), important);
5054        m_valueList->next();
5055        return true;
5056    }
5057    return false;
5058}
5059
5060PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeRectangle(CSSParserValueList* args)
5061{
5062    ASSERT(args);
5063
5064    // rect(x, y, width, height, [[rx], ry])
5065    if (args->size() != 7 && args->size() != 9 && args->size() != 11)
5066        return 0;
5067
5068    RefPtr<CSSBasicShapeRectangle> shape = CSSBasicShapeRectangle::create();
5069
5070    unsigned argumentNumber = 0;
5071    CSSParserValue* argument = args->current();
5072    while (argument) {
5073        Units unitFlags = FLength | FPercent;
5074        if (argumentNumber > 1) {
5075            // Arguments width, height, rx, and ry cannot be negative.
5076            unitFlags = unitFlags | FNonNeg;
5077        }
5078        if (!validUnit(argument, unitFlags))
5079            return 0;
5080
5081        RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5082        ASSERT(argumentNumber < 6);
5083        switch (argumentNumber) {
5084        case 0:
5085            shape->setX(length);
5086            break;
5087        case 1:
5088            shape->setY(length);
5089            break;
5090        case 2:
5091            shape->setWidth(length);
5092            break;
5093        case 3:
5094            shape->setHeight(length);
5095            break;
5096        case 4:
5097            shape->setRadiusX(length);
5098            break;
5099        case 5:
5100            shape->setRadiusY(length);
5101            break;
5102        }
5103        argument = args->next();
5104        if (argument) {
5105            if (!isComma(argument))
5106                return 0;
5107
5108            argument = args->next();
5109        }
5110        argumentNumber++;
5111    }
5112
5113    if (argumentNumber < 4)
5114        return 0;
5115    return shape;
5116}
5117
5118PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeInsetRectangle(CSSParserValueList* args)
5119{
5120    ASSERT(args);
5121
5122    // inset-rectangle(top, right, bottom, left, [[rx], ry])
5123    if (args->size() != 7 && args->size() != 9 && args->size() != 11)
5124        return 0;
5125
5126    RefPtr<CSSBasicShapeInsetRectangle> shape = CSSBasicShapeInsetRectangle::create();
5127
5128    unsigned argumentNumber = 0;
5129    CSSParserValue* argument = args->current();
5130    while (argument) {
5131        Units unitFlags = FLength | FPercent | FNonNeg;
5132        if (!validUnit(argument, unitFlags))
5133            return 0;
5134
5135        RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5136        ASSERT(argumentNumber < 6);
5137        switch (argumentNumber) {
5138        case 0:
5139            shape->setTop(length);
5140            break;
5141        case 1:
5142            shape->setRight(length);
5143            break;
5144        case 2:
5145            shape->setBottom(length);
5146            break;
5147        case 3:
5148            shape->setLeft(length);
5149            break;
5150        case 4:
5151            shape->setRadiusX(length);
5152            break;
5153        case 5:
5154            shape->setRadiusY(length);
5155            break;
5156        }
5157        argument = args->next();
5158        if (argument) {
5159            if (!isComma(argument))
5160                return 0;
5161
5162            argument = args->next();
5163        }
5164        argumentNumber++;
5165    }
5166
5167    if (argumentNumber < 4)
5168        return 0;
5169    return shape;
5170}
5171
5172PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeCircle(CSSParserValueList* args)
5173{
5174    ASSERT(args);
5175
5176    // circle(centerX, centerY, radius)
5177    if (args->size() != 5)
5178        return 0;
5179
5180    RefPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
5181
5182    unsigned argumentNumber = 0;
5183    CSSParserValue* argument = args->current();
5184    while (argument) {
5185        Units unitFlags = FLength | FPercent;
5186        if (argumentNumber == 2) {
5187            // Argument radius cannot be negative.
5188            unitFlags = unitFlags | FNonNeg;
5189        }
5190
5191        if (!validUnit(argument, unitFlags))
5192            return 0;
5193
5194        RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5195        ASSERT(argumentNumber < 3);
5196        switch (argumentNumber) {
5197        case 0:
5198            shape->setCenterX(length);
5199            break;
5200        case 1:
5201            shape->setCenterY(length);
5202            break;
5203        case 2:
5204            shape->setRadius(length);
5205            break;
5206        }
5207
5208        argument = args->next();
5209        if (argument) {
5210            if (!isComma(argument))
5211                return 0;
5212            argument = args->next();
5213        }
5214        argumentNumber++;
5215    }
5216
5217    if (argumentNumber < 3)
5218        return 0;
5219    return shape;
5220}
5221
5222PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeEllipse(CSSParserValueList* args)
5223{
5224    ASSERT(args);
5225
5226    // ellipse(centerX, centerY, radiusX, radiusY)
5227    if (args->size() != 7)
5228        return 0;
5229
5230    RefPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
5231    unsigned argumentNumber = 0;
5232    CSSParserValue* argument = args->current();
5233    while (argument) {
5234        Units unitFlags = FLength | FPercent;
5235        if (argumentNumber > 1) {
5236            // Arguments radiusX and radiusY cannot be negative.
5237            unitFlags = unitFlags | FNonNeg;
5238        }
5239        if (!validUnit(argument, unitFlags))
5240            return 0;
5241
5242        RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5243        ASSERT(argumentNumber < 4);
5244        switch (argumentNumber) {
5245        case 0:
5246            shape->setCenterX(length);
5247            break;
5248        case 1:
5249            shape->setCenterY(length);
5250            break;
5251        case 2:
5252            shape->setRadiusX(length);
5253            break;
5254        case 3:
5255            shape->setRadiusY(length);
5256            break;
5257        }
5258
5259        argument = args->next();
5260        if (argument) {
5261            if (!isComma(argument))
5262                return 0;
5263            argument = args->next();
5264        }
5265        argumentNumber++;
5266    }
5267
5268    if (argumentNumber < 4)
5269        return 0;
5270    return shape;
5271}
5272
5273PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapePolygon(CSSParserValueList* args)
5274{
5275    ASSERT(args);
5276
5277    unsigned size = args->size();
5278    if (!size)
5279        return 0;
5280
5281    RefPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
5282
5283    CSSParserValue* argument = args->current();
5284    if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
5285        shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
5286
5287        if (!isComma(args->next()))
5288            return 0;
5289
5290        argument = args->next();
5291        size -= 2;
5292    }
5293
5294    // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one
5295    if (!size || (size % 3) - 2)
5296        return 0;
5297
5298    CSSParserValue* argumentX = argument;
5299    while (argumentX) {
5300        if (!validUnit(argumentX, FLength | FPercent))
5301            return 0;
5302
5303        CSSParserValue* argumentY = args->next();
5304        if (!argumentY || !validUnit(argumentY, FLength | FPercent))
5305            return 0;
5306
5307        RefPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX);
5308        RefPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY);
5309
5310        shape->appendPoint(xLength.release(), yLength.release());
5311
5312        CSSParserValue* commaOrNull = args->next();
5313        if (!commaOrNull)
5314            argumentX = 0;
5315        else if (!isComma(commaOrNull))
5316            return 0;
5317        else
5318            argumentX = args->next();
5319    }
5320
5321    return shape;
5322}
5323
5324bool CSSParser::parseBasicShape(CSSPropertyID propId, bool important)
5325{
5326    CSSParserValue* value = m_valueList->current();
5327    ASSERT(value->unit == CSSParserValue::Function);
5328    CSSParserValueList* args = value->function->args.get();
5329
5330    if (!args)
5331        return false;
5332
5333    RefPtr<CSSBasicShape> shape;
5334    if (equalIgnoringCase(value->function->name, "rectangle("))
5335        shape = parseBasicShapeRectangle(args);
5336    else if (equalIgnoringCase(value->function->name, "circle("))
5337        shape = parseBasicShapeCircle(args);
5338    else if (equalIgnoringCase(value->function->name, "ellipse("))
5339        shape = parseBasicShapeEllipse(args);
5340    else if (equalIgnoringCase(value->function->name, "polygon("))
5341        shape = parseBasicShapePolygon(args);
5342    else if (equalIgnoringCase(value->function->name, "inset-rectangle("))
5343        shape = parseBasicShapeInsetRectangle(args);
5344
5345    if (!shape)
5346        return false;
5347
5348    addProperty(propId, cssValuePool().createValue(shape.release()), important);
5349    m_valueList->next();
5350    return true;
5351}
5352
5353// [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
5354bool CSSParser::parseFont(bool important)
5355{
5356    // Let's check if there is an inherit or initial somewhere in the shorthand.
5357    for (unsigned i = 0; i < m_valueList->size(); ++i) {
5358        if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial)
5359            return false;
5360    }
5361
5362    ShorthandScope scope(this, CSSPropertyFont);
5363    // Optional font-style, font-variant and font-weight.
5364    bool fontStyleParsed = false;
5365    bool fontVariantParsed = false;
5366    bool fontWeightParsed = false;
5367    CSSParserValue* value;
5368    while ((value = m_valueList->current())) {
5369        if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
5370            addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
5371            fontStyleParsed = true;
5372        } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
5373            // Font variant in the shorthand is particular, it only accepts normal or small-caps.
5374            addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important);
5375            fontVariantParsed = true;
5376        } else if (!fontWeightParsed && parseFontWeight(important))
5377            fontWeightParsed = true;
5378        else
5379            break;
5380        m_valueList->next();
5381    }
5382
5383    if (!value)
5384        return false;
5385
5386    if (!fontStyleParsed)
5387        addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5388    if (!fontVariantParsed)
5389        addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5390    if (!fontWeightParsed)
5391        addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5392
5393    // Now a font size _must_ come.
5394    // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
5395    if (!parseFontSize(important))
5396        return false;
5397
5398    value = m_valueList->current();
5399    if (!value)
5400        return false;
5401
5402    if (isForwardSlashOperator(value)) {
5403        // The line-height property.
5404        value = m_valueList->next();
5405        if (!value)
5406            return false;
5407        if (!parseLineHeight(important))
5408            return false;
5409    } else
5410        addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5411
5412    // Font family must come now.
5413    RefPtr<CSSValue> parsedFamilyValue = parseFontFamily();
5414    if (!parsedFamilyValue)
5415        return false;
5416
5417    addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
5418
5419    // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
5420    // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
5421    // but we don't seem to support them at the moment. They should also be added here once implemented.
5422    if (m_valueList->current())
5423        return false;
5424
5425    return true;
5426}
5427
5428class FontFamilyValueBuilder {
5429public:
5430    FontFamilyValueBuilder(CSSValueList* list)
5431        : m_list(list)
5432    {
5433    }
5434
5435    void add(const CSSParserString& string)
5436    {
5437        if (!m_builder.isEmpty())
5438            m_builder.append(' ');
5439
5440        if (string.is8Bit()) {
5441            m_builder.append(string.characters8(), string.length());
5442            return;
5443        }
5444
5445        m_builder.append(string.characters16(), string.length());
5446    }
5447
5448    void commit()
5449    {
5450        if (m_builder.isEmpty())
5451            return;
5452        m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString()));
5453        m_builder.clear();
5454    }
5455
5456private:
5457    StringBuilder m_builder;
5458    CSSValueList* m_list;
5459};
5460
5461PassRefPtr<CSSValueList> CSSParser::parseFontFamily()
5462{
5463    RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
5464    CSSParserValue* value = m_valueList->current();
5465
5466    FontFamilyValueBuilder familyBuilder(list.get());
5467    bool inFamily = false;
5468
5469    while (value) {
5470        CSSParserValue* nextValue = m_valueList->next();
5471        bool nextValBreaksFont = !nextValue ||
5472                                 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
5473        bool nextValIsFontName = nextValue &&
5474            ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
5475            (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
5476
5477        bool valueIsKeyword = value->id == CSSValueInitial || value->id == CSSValueInherit || value->id == CSSValueDefault;
5478        if (valueIsKeyword && !inFamily) {
5479            if (nextValBreaksFont)
5480                value = m_valueList->next();
5481            else if (nextValIsFontName)
5482                value = nextValue;
5483            continue;
5484        }
5485
5486        if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
5487            if (inFamily)
5488                familyBuilder.add(value->string);
5489            else if (nextValBreaksFont || !nextValIsFontName)
5490                list->append(cssValuePool().createIdentifierValue(value->id));
5491            else {
5492                familyBuilder.commit();
5493                familyBuilder.add(value->string);
5494                inFamily = true;
5495            }
5496        } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
5497            // Strings never share in a family name.
5498            inFamily = false;
5499            familyBuilder.commit();
5500            list->append(cssValuePool().createFontFamilyValue(value->string));
5501        } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
5502            if (inFamily)
5503                familyBuilder.add(value->string);
5504            else if (nextValBreaksFont || !nextValIsFontName)
5505                list->append(cssValuePool().createFontFamilyValue(value->string));
5506            else {
5507                familyBuilder.commit();
5508                familyBuilder.add(value->string);
5509                inFamily = true;
5510            }
5511        } else {
5512            break;
5513        }
5514
5515        if (!nextValue)
5516            break;
5517
5518        if (nextValBreaksFont) {
5519            value = m_valueList->next();
5520            familyBuilder.commit();
5521            inFamily = false;
5522        }
5523        else if (nextValIsFontName)
5524            value = nextValue;
5525        else
5526            break;
5527    }
5528    familyBuilder.commit();
5529
5530    if (!list->length())
5531        list = 0;
5532    return list.release();
5533}
5534
5535bool CSSParser::parseLineHeight(bool important)
5536{
5537    CSSParserValue* value = m_valueList->current();
5538    CSSValueID id = value->id;
5539    bool validPrimitive = false;
5540    // normal | <number> | <length> | <percentage> | inherit
5541    if (id == CSSValueNormal)
5542        validPrimitive = true;
5543    else
5544        validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
5545    if (validPrimitive && (!m_valueList->next() || inShorthand()))
5546        addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important);
5547    return validPrimitive;
5548}
5549
5550bool CSSParser::parseFontSize(bool important)
5551{
5552    CSSParserValue* value = m_valueList->current();
5553    CSSValueID id = value->id;
5554    bool validPrimitive = false;
5555    // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
5556    if (id >= CSSValueXxSmall && id <= CSSValueLarger)
5557        validPrimitive = true;
5558    else
5559        validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
5560    if (validPrimitive && (!m_valueList->next() || inShorthand()))
5561        addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important);
5562    return validPrimitive;
5563}
5564
5565bool CSSParser::parseFontVariant(bool important)
5566{
5567    RefPtr<CSSValueList> values;
5568    if (m_valueList->size() > 1)
5569        values = CSSValueList::createCommaSeparated();
5570    CSSParserValue* val;
5571    bool expectComma = false;
5572    while ((val = m_valueList->current())) {
5573        RefPtr<CSSPrimitiveValue> parsedValue;
5574        if (!expectComma) {
5575            expectComma = true;
5576            if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
5577                parsedValue = cssValuePool().createIdentifierValue(val->id);
5578            else if (val->id == CSSValueAll && !values) {
5579                // 'all' is only allowed in @font-face and with no other values. Make a value list to
5580                // indicate that we are in the @font-face case.
5581                values = CSSValueList::createCommaSeparated();
5582                parsedValue = cssValuePool().createIdentifierValue(val->id);
5583            }
5584        } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
5585            expectComma = false;
5586            m_valueList->next();
5587            continue;
5588        }
5589
5590        if (!parsedValue)
5591            return false;
5592
5593        m_valueList->next();
5594
5595        if (values)
5596            values->append(parsedValue.release());
5597        else {
5598            addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
5599            return true;
5600        }
5601    }
5602
5603    if (values && values->length()) {
5604        m_hasFontFaceOnlyValues = true;
5605        addProperty(CSSPropertyFontVariant, values.release(), important);
5606        return true;
5607    }
5608
5609    return false;
5610}
5611
5612bool CSSParser::parseFontWeight(bool important)
5613{
5614    CSSParserValue* value = m_valueList->current();
5615    if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
5616        addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important);
5617        return true;
5618    }
5619    if (validUnit(value, FInteger | FNonNeg, HTMLQuirksMode)) {
5620        int weight = static_cast<int>(value->fValue);
5621        if (!(weight % 100) && weight >= 100 && weight <= 900) {
5622            addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1)), important);
5623            return true;
5624        }
5625    }
5626    return false;
5627}
5628
5629bool CSSParser::parseFontFaceSrcURI(CSSValueList* valueList)
5630{
5631    RefPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string)));
5632
5633    CSSParserValue* value = m_valueList->next();
5634    if (!value) {
5635        valueList->append(uriValue.release());
5636        return true;
5637    }
5638    if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
5639        m_valueList->next();
5640        valueList->append(uriValue.release());
5641        return true;
5642    }
5643
5644    if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format("))
5645        return false;
5646
5647    // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
5648    // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
5649    CSSParserValueList* args = value->function->args.get();
5650    if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
5651        return false;
5652    uriValue->setFormat(args->current()->string);
5653    valueList->append(uriValue.release());
5654    value = m_valueList->next();
5655    if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
5656        m_valueList->next();
5657    return true;
5658}
5659
5660bool CSSParser::parseFontFaceSrcLocal(CSSValueList* valueList)
5661{
5662    CSSParserValueList* args = m_valueList->current()->function->args.get();
5663    if (!args || !args->size())
5664        return false;
5665
5666    if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING)
5667        valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string));
5668    else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
5669        StringBuilder builder;
5670        for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) {
5671            if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
5672                return false;
5673            if (!builder.isEmpty())
5674                builder.append(' ');
5675            builder.append(localValue->string);
5676        }
5677        valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
5678    } else
5679        return false;
5680
5681    if (CSSParserValue* value = m_valueList->next()) {
5682        if (value->unit == CSSParserValue::Operator && value->iValue == ',')
5683            m_valueList->next();
5684    }
5685    return true;
5686}
5687
5688bool CSSParser::parseFontFaceSrc()
5689{
5690    RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
5691
5692    while (CSSParserValue* value = m_valueList->current()) {
5693        if (value->unit == CSSPrimitiveValue::CSS_URI) {
5694            if (!parseFontFaceSrcURI(values.get()))
5695                return false;
5696        } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) {
5697            if (!parseFontFaceSrcLocal(values.get()))
5698                return false;
5699        } else
5700            return false;
5701    }
5702    if (!values->length())
5703        return false;
5704
5705    addProperty(CSSPropertySrc, values.release(), m_important);
5706    m_valueList->next();
5707    return true;
5708}
5709
5710bool CSSParser::parseFontFaceUnicodeRange()
5711{
5712    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
5713    bool failed = false;
5714    bool operatorExpected = false;
5715    for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
5716        if (operatorExpected) {
5717            if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
5718                continue;
5719            failed = true;
5720            break;
5721        }
5722        if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
5723            failed = true;
5724            break;
5725        }
5726
5727        String rangeString = m_valueList->current()->string;
5728        UChar32 from = 0;
5729        UChar32 to = 0;
5730        unsigned length = rangeString.length();
5731
5732        if (length < 3) {
5733            failed = true;
5734            break;
5735        }
5736
5737        unsigned i = 2;
5738        while (i < length) {
5739            UChar c = rangeString[i];
5740            if (c == '-' || c == '?')
5741                break;
5742            from *= 16;
5743            if (c >= '0' && c <= '9')
5744                from += c - '0';
5745            else if (c >= 'A' && c <= 'F')
5746                from += 10 + c - 'A';
5747            else if (c >= 'a' && c <= 'f')
5748                from += 10 + c - 'a';
5749            else {
5750                failed = true;
5751                break;
5752            }
5753            i++;
5754        }
5755        if (failed)
5756            break;
5757
5758        if (i == length)
5759            to = from;
5760        else if (rangeString[i] == '?') {
5761            unsigned span = 1;
5762            while (i < length && rangeString[i] == '?') {
5763                span *= 16;
5764                from *= 16;
5765                i++;
5766            }
5767            if (i < length)
5768                failed = true;
5769            to = from + span - 1;
5770        } else {
5771            if (length < i + 2) {
5772                failed = true;
5773                break;
5774            }
5775            i++;
5776            while (i < length) {
5777                UChar c = rangeString[i];
5778                to *= 16;
5779                if (c >= '0' && c <= '9')
5780                    to += c - '0';
5781                else if (c >= 'A' && c <= 'F')
5782                    to += 10 + c - 'A';
5783                else if (c >= 'a' && c <= 'f')
5784                    to += 10 + c - 'a';
5785                else {
5786                    failed = true;
5787                    break;
5788                }
5789                i++;
5790            }
5791            if (failed)
5792                break;
5793        }
5794        if (from <= to)
5795            values->append(CSSUnicodeRangeValue::create(from, to));
5796    }
5797    if (failed || !values->length())
5798        return false;
5799    addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
5800    return true;
5801}
5802
5803// Returns the number of characters which form a valid double
5804// and are terminated by the given terminator character
5805template <typename CharacterType>
5806static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
5807{
5808    int length = end - string;
5809    if (length < 1)
5810        return 0;
5811
5812    bool decimalMarkSeen = false;
5813    int processedLength = 0;
5814
5815    for (int i = 0; i < length; ++i) {
5816        if (string[i] == terminator) {
5817            processedLength = i;
5818            break;
5819        }
5820        if (!isASCIIDigit(string[i])) {
5821            if (!decimalMarkSeen && string[i] == '.')
5822                decimalMarkSeen = true;
5823            else
5824                return 0;
5825        }
5826    }
5827
5828    if (decimalMarkSeen && processedLength == 1)
5829        return 0;
5830
5831    return processedLength;
5832}
5833
5834// Returns the number of characters consumed for parsing a valid double
5835// terminated by the given terminator character
5836template <typename CharacterType>
5837static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value)
5838{
5839    int length = checkForValidDouble(string, end, terminator);
5840    if (!length)
5841        return 0;
5842
5843    int position = 0;
5844    double localValue = 0;
5845
5846    // The consumed characters here are guaranteed to be
5847    // ASCII digits with or without a decimal mark
5848    for (; position < length; ++position) {
5849        if (string[position] == '.')
5850            break;
5851        localValue = localValue * 10 + string[position] - '0';
5852    }
5853
5854    if (++position == length) {
5855        value = localValue;
5856        return length;
5857    }
5858
5859    double fraction = 0;
5860    double scale = 1;
5861
5862    while (position < length && scale < MAX_SCALE) {
5863        fraction = fraction * 10 + string[position++] - '0';
5864        scale *= 10;
5865    }
5866
5867    value = localValue + fraction / scale;
5868    return length;
5869}
5870
5871template <typename CharacterType>
5872static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
5873{
5874    const CharacterType* current = string;
5875    double localValue = 0;
5876    bool negative = false;
5877    while (current != end && isHTMLSpace<CharacterType>(*current))
5878        current++;
5879    if (current != end && *current == '-') {
5880        negative = true;
5881        current++;
5882    }
5883    if (current == end || !isASCIIDigit(*current))
5884        return false;
5885    while (current != end && isASCIIDigit(*current)) {
5886        double newValue = localValue * 10 + *current++ - '0';
5887        if (newValue >= 255) {
5888            // Clamp values at 255.
5889            localValue = 255;
5890            while (current != end && isASCIIDigit(*current))
5891                ++current;
5892            break;
5893        }
5894        localValue = newValue;
5895    }
5896
5897    if (current == end)
5898        return false;
5899
5900    if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
5901        return false;
5902
5903    if (*current == '.') {
5904        // We already parsed the integral part, try to parse
5905        // the fraction part of the percentage value.
5906        double percentage = 0;
5907        int numCharactersParsed = parseDouble(current, end, '%', percentage);
5908        if (!numCharactersParsed)
5909            return false;
5910        current += numCharactersParsed;
5911        if (*current != '%')
5912            return false;
5913        localValue += percentage;
5914    }
5915
5916    if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
5917        return false;
5918
5919    if (*current == '%') {
5920        expect = CSSPrimitiveValue::CSS_PERCENTAGE;
5921        localValue = localValue / 100.0 * 256.0;
5922        // Clamp values at 255 for percentages over 100%
5923        if (localValue > 255)
5924            localValue = 255;
5925        current++;
5926    } else
5927        expect = CSSPrimitiveValue::CSS_NUMBER;
5928
5929    while (current != end && isHTMLSpace<CharacterType>(*current))
5930        current++;
5931    if (current == end || *current++ != terminator)
5932        return false;
5933    // Clamp negative values at zero.
5934    value = negative ? 0 : static_cast<int>(localValue);
5935    string = current;
5936    return true;
5937}
5938
5939template <typename CharacterType>
5940static inline bool isTenthAlpha(const CharacterType* string, const int length)
5941{
5942    // "0.X"
5943    if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
5944        return true;
5945
5946    // ".X"
5947    if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
5948        return true;
5949
5950    return false;
5951}
5952
5953template <typename CharacterType>
5954static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
5955{
5956    while (string != end && isHTMLSpace<CharacterType>(*string))
5957        string++;
5958
5959    bool negative = false;
5960
5961    if (string != end && *string == '-') {
5962        negative = true;
5963        string++;
5964    }
5965
5966    value = 0;
5967
5968    int length = end - string;
5969    if (length < 2)
5970        return false;
5971
5972    if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
5973        return false;
5974
5975    if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
5976        if (checkForValidDouble(string, end, terminator)) {
5977            value = negative ? 0 : 255;
5978            string = end;
5979            return true;
5980        }
5981        return false;
5982    }
5983
5984    if (length == 2 && string[0] != '.') {
5985        value = !negative && string[0] == '1' ? 255 : 0;
5986        string = end;
5987        return true;
5988    }
5989
5990    if (isTenthAlpha(string, length - 1)) {
5991        static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
5992        value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
5993        string = end;
5994        return true;
5995    }
5996
5997    double alpha = 0;
5998    if (!parseDouble(string, end, terminator, alpha))
5999        return false;
6000    value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
6001    string = end;
6002    return true;
6003}
6004
6005template <typename CharacterType>
6006static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
6007{
6008    if (length < 5)
6009        return false;
6010    return characters[4] == '('
6011        && isASCIIAlphaCaselessEqual(characters[0], 'r')
6012        && isASCIIAlphaCaselessEqual(characters[1], 'g')
6013        && isASCIIAlphaCaselessEqual(characters[2], 'b')
6014        && isASCIIAlphaCaselessEqual(characters[3], 'a');
6015}
6016
6017template <typename CharacterType>
6018static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
6019{
6020    if (length < 4)
6021        return false;
6022    return characters[3] == '('
6023        && isASCIIAlphaCaselessEqual(characters[0], 'r')
6024        && isASCIIAlphaCaselessEqual(characters[1], 'g')
6025        && isASCIIAlphaCaselessEqual(characters[2], 'b');
6026}
6027
6028template <typename CharacterType>
6029static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length , bool strict)
6030{
6031    CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
6032
6033    if (!strict && length >= 3) {
6034        if (characters[0] == '#') {
6035            if (Color::parseHexColor(characters + 1, length - 1, rgb))
6036                return true;
6037        } else {
6038            if (Color::parseHexColor(characters, length, rgb))
6039                return true;
6040        }
6041    }
6042
6043    // Try rgba() syntax.
6044    if (mightBeRGBA(characters, length)) {
6045        const CharacterType* current = characters + 5;
6046        const CharacterType* end = characters + length;
6047        int red;
6048        int green;
6049        int blue;
6050        int alpha;
6051
6052        if (!parseColorIntOrPercentage(current, end, ',', expect, red))
6053            return false;
6054        if (!parseColorIntOrPercentage(current, end, ',', expect, green))
6055            return false;
6056        if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
6057            return false;
6058        if (!parseAlphaValue(current, end, ')', alpha))
6059            return false;
6060        if (current != end)
6061            return false;
6062        rgb = makeRGBA(red, green, blue, alpha);
6063        return true;
6064    }
6065
6066    // Try rgb() syntax.
6067    if (mightBeRGB(characters, length)) {
6068        const CharacterType* current = characters + 4;
6069        const CharacterType* end = characters + length;
6070        int red;
6071        int green;
6072        int blue;
6073        if (!parseColorIntOrPercentage(current, end, ',', expect, red))
6074            return false;
6075        if (!parseColorIntOrPercentage(current, end, ',', expect, green))
6076            return false;
6077        if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
6078            return false;
6079        if (current != end)
6080            return false;
6081        rgb = makeRGB(red, green, blue);
6082        return true;
6083    }
6084
6085    return false;
6086}
6087
6088template<typename StringType>
6089bool CSSParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict)
6090{
6091    unsigned length = name.length();
6092    bool parseResult;
6093
6094    if (!length)
6095        return false;
6096
6097    if (name.is8Bit())
6098        parseResult = fastParseColorInternal(rgb, name.characters8(), length, strict);
6099    else
6100        parseResult = fastParseColorInternal(rgb, name.characters16(), length, strict);
6101
6102    if (parseResult)
6103        return true;
6104
6105    // Try named colors.
6106    Color tc;
6107    tc.setNamedColor(name);
6108    if (tc.isValid()) {
6109        rgb = tc.rgb();
6110        return true;
6111    }
6112    return false;
6113}
6114
6115inline double CSSParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc)
6116{
6117    const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue;
6118    if (releaseCalc == ReleaseParsedCalcValue)
6119        m_parsedCalculation.release();
6120    return result;
6121}
6122
6123bool CSSParser::isCalculation(CSSParserValue* value)
6124{
6125    return (value->unit == CSSParserValue::Function)
6126        && (equalIgnoringCase(value->function->name, "calc(")
6127            || equalIgnoringCase(value->function->name, "-webkit-calc(")
6128            || equalIgnoringCase(value->function->name, "-webkit-min(")
6129            || equalIgnoringCase(value->function->name, "-webkit-max("));
6130}
6131
6132inline int CSSParser::colorIntFromValue(CSSParserValue* v)
6133{
6134    bool isPercent;
6135
6136    if (m_parsedCalculation)
6137        isPercent = m_parsedCalculation->category() == CalcPercent;
6138    else
6139        isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
6140
6141    const double value = parsedDouble(v, ReleaseParsedCalcValue);
6142
6143    if (value <= 0.0)
6144        return 0;
6145
6146    if (isPercent) {
6147        if (value >= 100.0)
6148            return 255;
6149        return static_cast<int>(value * 256.0 / 100.0);
6150    }
6151
6152    if (value >= 255.0)
6153        return 255;
6154
6155    return static_cast<int>(value);
6156}
6157
6158bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
6159{
6160    CSSParserValueList* args = value->function->args.get();
6161    CSSParserValue* v = args->current();
6162    Units unitType = FUnknown;
6163    // Get the first value and its type
6164    if (validUnit(v, FInteger, HTMLStandardMode))
6165        unitType = FInteger;
6166    else if (validUnit(v, FPercent, HTMLStandardMode))
6167        unitType = FPercent;
6168    else
6169        return false;
6170
6171    colorArray[0] = colorIntFromValue(v);
6172    for (int i = 1; i < 3; i++) {
6173        v = args->next();
6174        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6175            return false;
6176        v = args->next();
6177        if (!validUnit(v, unitType, HTMLStandardMode))
6178            return false;
6179        colorArray[i] = colorIntFromValue(v);
6180    }
6181    if (parseAlpha) {
6182        v = args->next();
6183        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6184            return false;
6185        v = args->next();
6186        if (!validUnit(v, FNumber, HTMLStandardMode))
6187            return false;
6188        const double value = parsedDouble(v, ReleaseParsedCalcValue);
6189        // Convert the floating pointer number of alpha to an integer in the range [0, 256),
6190        // with an equal distribution across all 256 values.
6191        colorArray[3] = static_cast<int>(max(0.0, min(1.0, value)) * nextafter(256.0, 0.0));
6192    }
6193    return true;
6194}
6195
6196// The CSS3 specification defines the format of a HSL color as
6197// hsl(<number>, <percent>, <percent>)
6198// and with alpha, the format is
6199// hsla(<number>, <percent>, <percent>, <number>)
6200// The first value, HUE, is in an angle with a value between 0 and 360
6201bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
6202{
6203    CSSParserValueList* args = value->function->args.get();
6204    CSSParserValue* v = args->current();
6205    // Get the first value
6206    if (!validUnit(v, FNumber, HTMLStandardMode))
6207        return false;
6208    // normalize the Hue value and change it to be between 0 and 1.0
6209    colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0;
6210    for (int i = 1; i < 3; i++) {
6211        v = args->next();
6212        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6213            return false;
6214        v = args->next();
6215        if (!validUnit(v, FPercent, HTMLStandardMode))
6216            return false;
6217        colorArray[i] = max(0.0, min(100.0, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0
6218    }
6219    if (parseAlpha) {
6220        v = args->next();
6221        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6222            return false;
6223        v = args->next();
6224        if (!validUnit(v, FNumber, HTMLStandardMode))
6225            return false;
6226        colorArray[3] = max(0.0, min(1.0, parsedDouble(v, ReleaseParsedCalcValue)));
6227    }
6228    return true;
6229}
6230
6231PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value)
6232{
6233    RGBA32 c = Color::transparent;
6234    if (!parseColorFromValue(value ? value : m_valueList->current(), c))
6235        return 0;
6236    return cssValuePool().createColorValue(c);
6237}
6238
6239bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
6240{
6241    if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
6242        && value->fValue >= 0. && value->fValue < 1000000.) {
6243        String str = String::format("%06d", static_cast<int>((value->fValue+.5)));
6244        // FIXME: This should be strict parsing for SVG as well.
6245        if (!fastParseColor(c, str, !inQuirksMode()))
6246            return false;
6247    } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
6248                value->unit == CSSPrimitiveValue::CSS_IDENT ||
6249                (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
6250        if (!fastParseColor(c, value->string, !inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
6251            return false;
6252    } else if (value->unit == CSSParserValue::Function &&
6253                value->function->args != 0 &&
6254                value->function->args->size() == 5 /* rgb + two commas */ &&
6255                equalIgnoringCase(value->function->name, "rgb(")) {
6256        int colorValues[3];
6257        if (!parseColorParameters(value, colorValues, false))
6258            return false;
6259        c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
6260    } else {
6261        if (value->unit == CSSParserValue::Function &&
6262                value->function->args != 0 &&
6263                value->function->args->size() == 7 /* rgba + three commas */ &&
6264                equalIgnoringCase(value->function->name, "rgba(")) {
6265            int colorValues[4];
6266            if (!parseColorParameters(value, colorValues, true))
6267                return false;
6268            c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
6269        } else if (value->unit == CSSParserValue::Function &&
6270                    value->function->args != 0 &&
6271                    value->function->args->size() == 5 /* hsl + two commas */ &&
6272                    equalIgnoringCase(value->function->name, "hsl(")) {
6273            double colorValues[3];
6274            if (!parseHSLParameters(value, colorValues, false))
6275                return false;
6276            c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
6277        } else if (value->unit == CSSParserValue::Function &&
6278                    value->function->args != 0 &&
6279                    value->function->args->size() == 7 /* hsla + three commas */ &&
6280                    equalIgnoringCase(value->function->name, "hsla(")) {
6281            double colorValues[4];
6282            if (!parseHSLParameters(value, colorValues, true))
6283                return false;
6284            c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
6285        } else
6286            return false;
6287    }
6288
6289    return true;
6290}
6291
6292// This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
6293// without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
6294struct ShadowParseContext {
6295    ShadowParseContext(CSSPropertyID prop, CSSParser* parser)
6296        : property(prop)
6297        , m_parser(parser)
6298        , allowX(true)
6299        , allowY(false)
6300        , allowBlur(false)
6301        , allowSpread(false)
6302        , allowColor(true)
6303        , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
6304        , allowBreak(true)
6305    {
6306    }
6307
6308    bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
6309
6310    void commitValue()
6311    {
6312        // Handle the ,, case gracefully by doing nothing.
6313        if (x || y || blur || spread || color || style) {
6314            if (!values)
6315                values = CSSValueList::createCommaSeparated();
6316
6317            // Construct the current shadow value and add it to the list.
6318            values->append(CSSShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
6319        }
6320
6321        // Now reset for the next shadow value.
6322        x = 0;
6323        y = 0;
6324        blur = 0;
6325        spread = 0;
6326        style = 0;
6327        color = 0;
6328
6329        allowX = true;
6330        allowColor = true;
6331        allowBreak = true;
6332        allowY = false;
6333        allowBlur = false;
6334        allowSpread = false;
6335        allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6336    }
6337
6338    void commitLength(CSSParserValue* v)
6339    {
6340        RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
6341
6342        if (allowX) {
6343            x = val.release();
6344            allowX = false;
6345            allowY = true;
6346            allowColor = false;
6347            allowStyle = false;
6348            allowBreak = false;
6349        } else if (allowY) {
6350            y = val.release();
6351            allowY = false;
6352            allowBlur = true;
6353            allowColor = true;
6354            allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6355            allowBreak = true;
6356        } else if (allowBlur) {
6357            blur = val.release();
6358            allowBlur = false;
6359            allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6360        } else if (allowSpread) {
6361            spread = val.release();
6362            allowSpread = false;
6363        }
6364    }
6365
6366    void commitColor(PassRefPtr<CSSPrimitiveValue> val)
6367    {
6368        color = val;
6369        allowColor = false;
6370        if (allowX) {
6371            allowStyle = false;
6372            allowBreak = false;
6373        } else {
6374            allowBlur = false;
6375            allowSpread = false;
6376            allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6377        }
6378    }
6379
6380    void commitStyle(CSSParserValue* v)
6381    {
6382        style = cssValuePool().createIdentifierValue(v->id);
6383        allowStyle = false;
6384        if (allowX)
6385            allowBreak = false;
6386        else {
6387            allowBlur = false;
6388            allowSpread = false;
6389            allowColor = false;
6390        }
6391    }
6392
6393    CSSPropertyID property;
6394    CSSParser* m_parser;
6395
6396    RefPtr<CSSValueList> values;
6397    RefPtr<CSSPrimitiveValue> x;
6398    RefPtr<CSSPrimitiveValue> y;
6399    RefPtr<CSSPrimitiveValue> blur;
6400    RefPtr<CSSPrimitiveValue> spread;
6401    RefPtr<CSSPrimitiveValue> style;
6402    RefPtr<CSSPrimitiveValue> color;
6403
6404    bool allowX;
6405    bool allowY;
6406    bool allowBlur;
6407    bool allowSpread;
6408    bool allowColor;
6409    bool allowStyle; // inset or not.
6410    bool allowBreak;
6411};
6412
6413PassRefPtr<CSSValueList> CSSParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId)
6414{
6415    ShadowParseContext context(propId, this);
6416    CSSParserValue* val;
6417    while ((val = valueList->current())) {
6418        // Check for a comma break first.
6419        if (val->unit == CSSParserValue::Operator) {
6420            if (val->iValue != ',' || !context.allowBreak)
6421                // Other operators aren't legal or we aren't done with the current shadow
6422                // value.  Treat as invalid.
6423                return 0;
6424            // The value is good.  Commit it.
6425            context.commitValue();
6426        } else if (validUnit(val, FLength, HTMLStandardMode)) {
6427            // We required a length and didn't get one. Invalid.
6428            if (!context.allowLength())
6429                return 0;
6430
6431            // Blur radius must be non-negative.
6432            if (context.allowBlur && !validUnit(val, FLength | FNonNeg, HTMLStandardMode))
6433                return 0;
6434
6435            // A length is allowed here.  Construct the value and add it.
6436            context.commitLength(val);
6437        } else if (val->id == CSSValueInset) {
6438            if (!context.allowStyle)
6439                return 0;
6440
6441            context.commitStyle(val);
6442        } else {
6443            // The only other type of value that's ok is a color value.
6444            RefPtr<CSSPrimitiveValue> parsedColor;
6445            bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu
6446                            || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode())
6447                            || val->id == CSSValueCurrentcolor);
6448            if (isColor) {
6449                if (!context.allowColor)
6450                    return 0;
6451                parsedColor = cssValuePool().createIdentifierValue(val->id);
6452            }
6453
6454            if (!parsedColor)
6455                // It's not built-in. Try to parse it as a color.
6456                parsedColor = parseColor(val);
6457
6458            if (!parsedColor || !context.allowColor)
6459                return 0; // This value is not a color or length and is invalid or
6460                          // it is a color, but a color isn't allowed at this point.
6461
6462            context.commitColor(parsedColor.release());
6463        }
6464
6465        valueList->next();
6466    }
6467
6468    if (context.allowBreak) {
6469        context.commitValue();
6470        if (context.values && context.values->length())
6471            return context.values.release();
6472    }
6473
6474    return 0;
6475}
6476
6477bool CSSParser::parseReflect(CSSPropertyID propId, bool important)
6478{
6479    // box-reflect: <direction> <offset> <mask>
6480
6481    // Direction comes first.
6482    CSSParserValue* val = m_valueList->current();
6483    RefPtr<CSSPrimitiveValue> direction;
6484    if (val->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
6485        direction = createPrimitiveVariableNameValue(val);
6486    else
6487    switch (val->id) {
6488        case CSSValueAbove:
6489        case CSSValueBelow:
6490        case CSSValueLeft:
6491        case CSSValueRight:
6492            direction = cssValuePool().createIdentifierValue(val->id);
6493            break;
6494        default:
6495            return false;
6496    }
6497
6498    // The offset comes next.
6499    val = m_valueList->next();
6500    RefPtr<CSSPrimitiveValue> offset;
6501    if (!val)
6502        offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6503    else {
6504        if (!validUnit(val, FLength | FPercent))
6505            return false;
6506        offset = createPrimitiveNumericValue(val);
6507    }
6508
6509    // Now for the mask.
6510    RefPtr<CSSValue> mask;
6511    val = m_valueList->next();
6512    if (val) {
6513        mask = parseBorderImage(propId);
6514        if (!mask)
6515            return false;
6516    }
6517
6518    RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction.release(), offset.release(), mask.release());
6519    addProperty(propId, reflectValue.release(), important);
6520    m_valueList->next();
6521    return true;
6522}
6523
6524bool CSSParser::parseFlex(CSSParserValueList* args, bool important)
6525{
6526    if (!args || !args->size() || args->size() > 3)
6527        return false;
6528    static const double unsetValue = -1;
6529    double flexGrow = unsetValue;
6530    double flexShrink = unsetValue;
6531    RefPtr<CSSPrimitiveValue> flexBasis;
6532
6533    while (CSSParserValue* arg = args->current()) {
6534        if (validUnit(arg, FNumber | FNonNeg)) {
6535            if (flexGrow == unsetValue)
6536                flexGrow = arg->fValue;
6537            else if (flexShrink == unsetValue)
6538                flexShrink = arg->fValue;
6539            else if (!arg->fValue) {
6540                // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
6541                flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6542            } else {
6543                // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
6544                return false;
6545            }
6546        } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg)))
6547            flexBasis = parseValidPrimitive(arg->id, arg);
6548        else {
6549            // Not a valid arg for flex.
6550            return false;
6551        }
6552        args->next();
6553    }
6554
6555    if (flexGrow == unsetValue)
6556        flexGrow = 1;
6557    if (flexShrink == unsetValue)
6558        flexShrink = 1;
6559    if (!flexBasis)
6560        flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6561
6562    addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
6563    addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
6564    addProperty(CSSPropertyFlexBasis, flexBasis, important);
6565    return true;
6566}
6567
6568bool CSSParser::parseObjectPosition(bool important)
6569{
6570    RefPtr<CSSValue> xValue;
6571    RefPtr<CSSValue> yValue;
6572    parseFillPosition(m_valueList.get(), xValue, yValue);
6573    if (!xValue || !yValue)
6574        return false;
6575    addProperty(
6576        CSSPropertyObjectPosition,
6577        createPrimitiveValuePair(toCSSPrimitiveValue(xValue.get()), toCSSPrimitiveValue(yValue.get()), Pair::KeepIdenticalValues),
6578        important);
6579    return true;
6580}
6581
6582struct BorderImageParseContext {
6583    BorderImageParseContext()
6584    : m_canAdvance(false)
6585    , m_allowCommit(true)
6586    , m_allowImage(true)
6587    , m_allowImageSlice(true)
6588    , m_allowRepeat(true)
6589    , m_allowForwardSlashOperator(false)
6590    , m_requireWidth(false)
6591    , m_requireOutset(false)
6592    {}
6593
6594    bool canAdvance() const { return m_canAdvance; }
6595    void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
6596
6597    bool allowCommit() const { return m_allowCommit; }
6598    bool allowImage() const { return m_allowImage; }
6599    bool allowImageSlice() const { return m_allowImageSlice; }
6600    bool allowRepeat() const { return m_allowRepeat; }
6601    bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; }
6602
6603    bool requireWidth() const { return m_requireWidth; }
6604    bool requireOutset() const { return m_requireOutset; }
6605
6606    void commitImage(PassRefPtr<CSSValue> image)
6607    {
6608        m_image = image;
6609        m_canAdvance = true;
6610        m_allowCommit = true;
6611        m_allowImage = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
6612        m_allowImageSlice = !m_imageSlice;
6613        m_allowRepeat = !m_repeat;
6614    }
6615    void commitImageSlice(PassRefPtr<CSSBorderImageSliceValue> slice)
6616    {
6617        m_imageSlice = slice;
6618        m_canAdvance = true;
6619        m_allowCommit = m_allowForwardSlashOperator = true;
6620        m_allowImageSlice = m_requireWidth = m_requireOutset = false;
6621        m_allowImage = !m_image;
6622        m_allowRepeat = !m_repeat;
6623    }
6624    void commitForwardSlashOperator()
6625    {
6626        m_canAdvance = true;
6627        m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowForwardSlashOperator = false;
6628        if (!m_borderSlice) {
6629            m_requireWidth = true;
6630            m_requireOutset = false;
6631        } else {
6632            m_requireOutset = true;
6633            m_requireWidth = false;
6634        }
6635    }
6636    void commitBorderWidth(PassRefPtr<CSSPrimitiveValue> slice)
6637    {
6638        m_borderSlice = slice;
6639        m_canAdvance = true;
6640        m_allowCommit = m_allowForwardSlashOperator = true;
6641        m_allowImageSlice = m_requireWidth = m_requireOutset = false;
6642        m_allowImage = !m_image;
6643        m_allowRepeat = !m_repeat;
6644    }
6645    void commitBorderOutset(PassRefPtr<CSSPrimitiveValue> outset)
6646    {
6647        m_outset = outset;
6648        m_canAdvance = true;
6649        m_allowCommit = true;
6650        m_allowImageSlice = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
6651        m_allowImage = !m_image;
6652        m_allowRepeat = !m_repeat;
6653    }
6654    void commitRepeat(PassRefPtr<CSSValue> repeat)
6655    {
6656        m_repeat = repeat;
6657        m_canAdvance = true;
6658        m_allowCommit = true;
6659        m_allowRepeat = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
6660        m_allowImageSlice = !m_imageSlice;
6661        m_allowImage = !m_image;
6662    }
6663
6664    PassRefPtr<CSSValue> commitCSSValue()
6665    {
6666        return createBorderImageValue(m_image, m_imageSlice, m_borderSlice, m_outset, m_repeat);
6667    }
6668
6669    void commitMaskBoxImage(CSSParser* parser, bool important)
6670    {
6671        commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSource, parser, m_image, important);
6672        commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSlice, parser, m_imageSlice, important);
6673        commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageWidth, parser, m_borderSlice, important);
6674        commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageOutset, parser, m_outset, important);
6675        commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageRepeat, parser, m_repeat, important);
6676    }
6677
6678    void commitBorderImage(CSSParser* parser, bool important)
6679    {
6680        commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
6681        commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice, important);
6682        commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice, important);
6683        commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset, important);
6684        commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important);
6685    }
6686
6687    void commitBorderImageProperty(CSSPropertyID propId, CSSParser* parser, PassRefPtr<CSSValue> value, bool important)
6688    {
6689        if (value)
6690            parser->addProperty(propId, value, important);
6691        else
6692            parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true);
6693    }
6694
6695    bool m_canAdvance;
6696
6697    bool m_allowCommit;
6698    bool m_allowImage;
6699    bool m_allowImageSlice;
6700    bool m_allowRepeat;
6701    bool m_allowForwardSlashOperator;
6702
6703    bool m_requireWidth;
6704    bool m_requireOutset;
6705
6706    RefPtr<CSSValue> m_image;
6707    RefPtr<CSSBorderImageSliceValue> m_imageSlice;
6708    RefPtr<CSSPrimitiveValue> m_borderSlice;
6709    RefPtr<CSSPrimitiveValue> m_outset;
6710
6711    RefPtr<CSSValue> m_repeat;
6712};
6713
6714static bool buildBorderImageParseContext(CSSParser& parser, CSSPropertyID propId, BorderImageParseContext& context)
6715{
6716    ShorthandScope scope(&parser, propId);
6717    while (CSSParserValue* val = parser.m_valueList->current()) {
6718        context.setCanAdvance(false);
6719
6720        if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(val))
6721            context.commitForwardSlashOperator();
6722
6723        if (!context.canAdvance() && context.allowImage()) {
6724            if (val->unit == CSSPrimitiveValue::CSS_URI) {
6725                context.commitImage(CSSImageValue::create(parser.completeURL(parser.m_context, val->string)));
6726            } else if (isGeneratedImageValue(val)) {
6727                RefPtr<CSSValue> value;
6728                if (parser.parseGeneratedImage(parser.m_valueList.get(), value))
6729                    context.commitImage(value.release());
6730                else
6731                    return false;
6732            } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
6733                RefPtr<CSSValue> value = parser.parseImageSet(parser.m_valueList.get());
6734                if (value)
6735                    context.commitImage(value.release());
6736                else
6737                    return false;
6738            } else if (val->id == CSSValueNone)
6739                context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone));
6740        }
6741
6742        if (!context.canAdvance() && context.allowImageSlice()) {
6743            RefPtr<CSSBorderImageSliceValue> imageSlice;
6744            if (parser.parseBorderImageSlice(propId, imageSlice))
6745                context.commitImageSlice(imageSlice.release());
6746        }
6747
6748        if (!context.canAdvance() && context.allowRepeat()) {
6749            RefPtr<CSSValue> repeat;
6750            if (parser.parseBorderImageRepeat(repeat))
6751                context.commitRepeat(repeat.release());
6752        }
6753
6754        if (!context.canAdvance() && context.requireWidth()) {
6755            RefPtr<CSSPrimitiveValue> borderSlice;
6756            if (parser.parseBorderImageWidth(borderSlice))
6757                context.commitBorderWidth(borderSlice.release());
6758        }
6759
6760        if (!context.canAdvance() && context.requireOutset()) {
6761            RefPtr<CSSPrimitiveValue> borderOutset;
6762            if (parser.parseBorderImageOutset(borderOutset))
6763                context.commitBorderOutset(borderOutset.release());
6764        }
6765
6766        if (!context.canAdvance())
6767            return false;
6768
6769        parser.m_valueList->next();
6770    }
6771
6772    return context.allowCommit();
6773}
6774
6775bool CSSParser::parseBorderImageShorthand(CSSPropertyID propId, bool important)
6776{
6777    BorderImageParseContext context;
6778    if (buildBorderImageParseContext(*this, propId, context)) {
6779        switch (propId) {
6780        case CSSPropertyWebkitMaskBoxImage:
6781            context.commitMaskBoxImage(this, important);
6782            return true;
6783        case CSSPropertyBorderImage:
6784            context.commitBorderImage(this, important);
6785            return true;
6786        default:
6787            ASSERT_NOT_REACHED();
6788            return false;
6789        }
6790    }
6791    return false;
6792}
6793
6794PassRefPtr<CSSValue> CSSParser::parseBorderImage(CSSPropertyID propId)
6795{
6796    BorderImageParseContext context;
6797    if (buildBorderImageParseContext(*this, propId, context)) {
6798        return context.commitCSSValue();
6799    }
6800    return 0;
6801}
6802
6803static bool isBorderImageRepeatKeyword(int id)
6804{
6805    return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
6806}
6807
6808bool CSSParser::parseBorderImageRepeat(RefPtr<CSSValue>& result)
6809{
6810    RefPtr<CSSPrimitiveValue> firstValue;
6811    RefPtr<CSSPrimitiveValue> secondValue;
6812    CSSParserValue* val = m_valueList->current();
6813    if (!val)
6814        return false;
6815    if (isBorderImageRepeatKeyword(val->id))
6816        firstValue = cssValuePool().createIdentifierValue(val->id);
6817    else
6818        return false;
6819
6820    val = m_valueList->next();
6821    if (val) {
6822        if (isBorderImageRepeatKeyword(val->id))
6823            secondValue = cssValuePool().createIdentifierValue(val->id);
6824        else if (!inShorthand()) {
6825            // If we're not parsing a shorthand then we are invalid.
6826            return false;
6827        } else {
6828            // We need to rewind the value list, so that when its advanced we'll
6829            // end up back at this value.
6830            m_valueList->previous();
6831            secondValue = firstValue;
6832        }
6833    } else
6834        secondValue = firstValue;
6835
6836    result = createPrimitiveValuePair(firstValue, secondValue);
6837    return true;
6838}
6839
6840class BorderImageSliceParseContext {
6841public:
6842    BorderImageSliceParseContext(CSSParser* parser)
6843    : m_parser(parser)
6844    , m_allowNumber(true)
6845    , m_allowFill(true)
6846    , m_allowFinalCommit(false)
6847    , m_fill(false)
6848    { }
6849
6850    bool allowNumber() const { return m_allowNumber; }
6851    bool allowFill() const { return m_allowFill; }
6852    bool allowFinalCommit() const { return m_allowFinalCommit; }
6853    CSSPrimitiveValue* top() const { return m_top.get(); }
6854
6855    void commitNumber(CSSParserValue* v)
6856    {
6857        RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
6858        if (!m_top)
6859            m_top = val;
6860        else if (!m_right)
6861            m_right = val;
6862        else if (!m_bottom)
6863            m_bottom = val;
6864        else {
6865            ASSERT(!m_left);
6866            m_left = val;
6867        }
6868
6869        m_allowNumber = !m_left;
6870        m_allowFinalCommit = true;
6871    }
6872
6873    void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; }
6874
6875    PassRefPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
6876    {
6877        // We need to clone and repeat values for any omissions.
6878        ASSERT(m_top);
6879        if (!m_right) {
6880            m_right = m_top;
6881            m_bottom = m_top;
6882            m_left = m_top;
6883        }
6884        if (!m_bottom) {
6885            m_bottom = m_top;
6886            m_left = m_right;
6887        }
6888        if (!m_left)
6889            m_left = m_right;
6890
6891        // Now build a rect value to hold all four of our primitive values.
6892        RefPtr<Quad> quad = Quad::create();
6893        quad->setTop(m_top);
6894        quad->setRight(m_right);
6895        quad->setBottom(m_bottom);
6896        quad->setLeft(m_left);
6897
6898        // Make our new border image value now.
6899        return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill);
6900    }
6901
6902private:
6903    CSSParser* m_parser;
6904
6905    bool m_allowNumber;
6906    bool m_allowFill;
6907    bool m_allowFinalCommit;
6908
6909    RefPtr<CSSPrimitiveValue> m_top;
6910    RefPtr<CSSPrimitiveValue> m_right;
6911    RefPtr<CSSPrimitiveValue> m_bottom;
6912    RefPtr<CSSPrimitiveValue> m_left;
6913
6914    bool m_fill;
6915};
6916
6917bool CSSParser::parseBorderImageSlice(CSSPropertyID propId, RefPtr<CSSBorderImageSliceValue>& result)
6918{
6919    BorderImageSliceParseContext context(this);
6920    CSSParserValue* val;
6921    while ((val = m_valueList->current())) {
6922        // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
6923        if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, HTMLStandardMode)) {
6924            context.commitNumber(val);
6925        } else if (context.allowFill() && val->id == CSSValueFill)
6926            context.commitFill();
6927        else if (!inShorthand()) {
6928            // If we're not parsing a shorthand then we are invalid.
6929            return false;
6930        } else {
6931            if (context.allowFinalCommit()) {
6932                // We're going to successfully parse, but we don't want to consume this token.
6933                m_valueList->previous();
6934            }
6935            break;
6936        }
6937        m_valueList->next();
6938    }
6939
6940    if (context.allowFinalCommit()) {
6941        // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
6942        // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
6943        if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
6944            context.commitFill();
6945
6946        // Need to fully commit as a single value.
6947        result = context.commitBorderImageSlice();
6948        return true;
6949    }
6950
6951    return false;
6952}
6953
6954class BorderImageQuadParseContext {
6955public:
6956    BorderImageQuadParseContext(CSSParser* parser)
6957    : m_parser(parser)
6958    , m_allowNumber(true)
6959    , m_allowFinalCommit(false)
6960    { }
6961
6962    bool allowNumber() const { return m_allowNumber; }
6963    bool allowFinalCommit() const { return m_allowFinalCommit; }
6964    CSSPrimitiveValue* top() const { return m_top.get(); }
6965
6966    void commitNumber(CSSParserValue* v)
6967    {
6968        RefPtr<CSSPrimitiveValue> val;
6969        if (v->id == CSSValueAuto)
6970            val = cssValuePool().createIdentifierValue(v->id);
6971        else
6972            val = m_parser->createPrimitiveNumericValue(v);
6973
6974        if (!m_top)
6975            m_top = val;
6976        else if (!m_right)
6977            m_right = val;
6978        else if (!m_bottom)
6979            m_bottom = val;
6980        else {
6981            ASSERT(!m_left);
6982            m_left = val;
6983        }
6984
6985        m_allowNumber = !m_left;
6986        m_allowFinalCommit = true;
6987    }
6988
6989    void setAllowFinalCommit() { m_allowFinalCommit = true; }
6990    void setTop(PassRefPtr<CSSPrimitiveValue> val) { m_top = val; }
6991
6992    PassRefPtr<CSSPrimitiveValue> commitBorderImageQuad()
6993    {
6994        // We need to clone and repeat values for any omissions.
6995        ASSERT(m_top);
6996        if (!m_right) {
6997            m_right = m_top;
6998            m_bottom = m_top;
6999            m_left = m_top;
7000        }
7001        if (!m_bottom) {
7002            m_bottom = m_top;
7003            m_left = m_right;
7004        }
7005        if (!m_left)
7006            m_left = m_right;
7007
7008        // Now build a quad value to hold all four of our primitive values.
7009        RefPtr<Quad> quad = Quad::create();
7010        quad->setTop(m_top);
7011        quad->setRight(m_right);
7012        quad->setBottom(m_bottom);
7013        quad->setLeft(m_left);
7014
7015        // Make our new value now.
7016        return cssValuePool().createValue(quad.release());
7017    }
7018
7019private:
7020    CSSParser* m_parser;
7021
7022    bool m_allowNumber;
7023    bool m_allowFinalCommit;
7024
7025    RefPtr<CSSPrimitiveValue> m_top;
7026    RefPtr<CSSPrimitiveValue> m_right;
7027    RefPtr<CSSPrimitiveValue> m_bottom;
7028    RefPtr<CSSPrimitiveValue> m_left;
7029};
7030
7031bool CSSParser::parseBorderImageQuad(Units validUnits, RefPtr<CSSPrimitiveValue>& result)
7032{
7033    BorderImageQuadParseContext context(this);
7034    CSSParserValue* val;
7035    while ((val = m_valueList->current())) {
7036        if (context.allowNumber() && (validUnit(val, validUnits, HTMLStandardMode) || val->id == CSSValueAuto)) {
7037            context.commitNumber(val);
7038        } else if (!inShorthand()) {
7039            // If we're not parsing a shorthand then we are invalid.
7040            return false;
7041        } else {
7042            if (context.allowFinalCommit())
7043                m_valueList->previous(); // The shorthand loop will advance back to this point.
7044            break;
7045        }
7046        m_valueList->next();
7047    }
7048
7049    if (context.allowFinalCommit()) {
7050        // Need to fully commit as a single value.
7051        result = context.commitBorderImageQuad();
7052        return true;
7053    }
7054    return false;
7055}
7056
7057bool CSSParser::parseBorderImageWidth(RefPtr<CSSPrimitiveValue>& result)
7058{
7059    return parseBorderImageQuad(FLength | FNumber | FNonNeg | FPercent, result);
7060}
7061
7062bool CSSParser::parseBorderImageOutset(RefPtr<CSSPrimitiveValue>& result)
7063{
7064    return parseBorderImageQuad(FLength | FNumber | FNonNeg, result);
7065}
7066
7067static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4])
7068{
7069    if (radii[3])
7070        return;
7071    if (!radii[2]) {
7072        if (!radii[1])
7073            radii[1] = radii[0];
7074        radii[2] = radii[0];
7075    }
7076    radii[3] = radii[1];
7077}
7078
7079bool CSSParser::parseBorderRadius(CSSPropertyID propId, bool important)
7080{
7081    unsigned num = m_valueList->size();
7082    if (num > 9)
7083        return false;
7084
7085    ShorthandScope scope(this, propId);
7086    RefPtr<CSSPrimitiveValue> radii[2][4];
7087
7088    unsigned indexAfterSlash = 0;
7089    for (unsigned i = 0; i < num; ++i) {
7090        CSSParserValue* value = m_valueList->valueAt(i);
7091        if (value->unit == CSSParserValue::Operator) {
7092            if (value->iValue != '/')
7093                return false;
7094
7095            if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
7096                return false;
7097
7098            indexAfterSlash = i + 1;
7099            completeBorderRadii(radii[0]);
7100            continue;
7101        }
7102
7103        if (i - indexAfterSlash >= 4)
7104            return false;
7105
7106        if (!validUnit(value, FLength | FPercent | FNonNeg))
7107            return false;
7108
7109        RefPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
7110
7111        if (!indexAfterSlash) {
7112            radii[0][i] = radius;
7113
7114            // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
7115            if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
7116                indexAfterSlash = 1;
7117                completeBorderRadii(radii[0]);
7118            }
7119        } else
7120            radii[1][i - indexAfterSlash] = radius.release();
7121    }
7122
7123    if (!indexAfterSlash) {
7124        completeBorderRadii(radii[0]);
7125        for (unsigned i = 0; i < 4; ++i)
7126            radii[1][i] = radii[0][i];
7127    } else
7128        completeBorderRadii(radii[1]);
7129
7130    ImplicitScope implicitScope(this, PropertyImplicit);
7131    addProperty(CSSPropertyBorderTopLeftRadius, createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()), important);
7132    addProperty(CSSPropertyBorderTopRightRadius, createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()), important);
7133    addProperty(CSSPropertyBorderBottomRightRadius, createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()), important);
7134    addProperty(CSSPropertyBorderBottomLeftRadius, createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()), important);
7135    return true;
7136}
7137
7138bool CSSParser::parseAspectRatio(bool important)
7139{
7140    unsigned num = m_valueList->size();
7141    if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
7142        addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(CSSValueNone), important);
7143        return true;
7144    }
7145
7146    if (num != 3)
7147        return false;
7148
7149    CSSParserValue* lvalue = m_valueList->valueAt(0);
7150    CSSParserValue* op = m_valueList->valueAt(1);
7151    CSSParserValue* rvalue = m_valueList->valueAt(2);
7152
7153    if (!isForwardSlashOperator(op))
7154        return false;
7155
7156    if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
7157        return false;
7158
7159    if (!lvalue->fValue || !rvalue->fValue)
7160        return false;
7161
7162    addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important);
7163
7164    return true;
7165}
7166
7167bool CSSParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important)
7168{
7169    enum { ID, VAL } state = ID;
7170
7171    RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
7172    RefPtr<CSSPrimitiveValue> counterName;
7173
7174    while (true) {
7175        CSSParserValue* val = m_valueList->current();
7176        switch (state) {
7177            case ID:
7178                if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
7179                    counterName = createPrimitiveStringValue(val);
7180                    state = VAL;
7181                    m_valueList->next();
7182                    continue;
7183                }
7184                break;
7185            case VAL: {
7186                int i = defaultValue;
7187                if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
7188                    i = clampToInteger(val->fValue);
7189                    m_valueList->next();
7190                }
7191
7192                list->append(createPrimitiveValuePair(counterName.release(),
7193                    cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER)));
7194                state = ID;
7195                continue;
7196            }
7197        }
7198        break;
7199    }
7200
7201    if (list->length() > 0) {
7202        addProperty(propId, list.release(), important);
7203        return true;
7204    }
7205
7206    return false;
7207}
7208
7209// This should go away once we drop support for -webkit-gradient
7210static PassRefPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
7211{
7212    RefPtr<CSSPrimitiveValue> result;
7213    if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
7214        if ((equalIgnoringCase(a, "left") && horizontal)
7215            || (equalIgnoringCase(a, "top") && !horizontal))
7216            result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
7217        else if ((equalIgnoringCase(a, "right") && horizontal)
7218                 || (equalIgnoringCase(a, "bottom") && !horizontal))
7219            result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
7220        else if (equalIgnoringCase(a, "center"))
7221            result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
7222    } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7223        result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(a->unit));
7224    return result;
7225}
7226
7227static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
7228{
7229    if (a->unit != CSSParserValue::Function)
7230        return false;
7231
7232    if (!equalIgnoringCase(a->function->name, "from(") &&
7233        !equalIgnoringCase(a->function->name, "to(") &&
7234        !equalIgnoringCase(a->function->name, "color-stop("))
7235        return false;
7236
7237    CSSParserValueList* args = a->function->args.get();
7238    if (!args)
7239        return false;
7240
7241    if (equalIgnoringCase(a->function->name, "from(")
7242        || equalIgnoringCase(a->function->name, "to(")) {
7243        // The "from" and "to" stops expect 1 argument.
7244        if (args->size() != 1)
7245            return false;
7246
7247        if (equalIgnoringCase(a->function->name, "from("))
7248            stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
7249        else
7250            stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
7251
7252        CSSValueID id = args->current()->id;
7253        if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
7254            stop.m_color = cssValuePool().createIdentifierValue(id);
7255        else
7256            stop.m_color = p->parseColor(args->current());
7257        if (!stop.m_color)
7258            return false;
7259    }
7260
7261    // The "color-stop" function expects 3 arguments.
7262    if (equalIgnoringCase(a->function->name, "color-stop(")) {
7263        if (args->size() != 3)
7264            return false;
7265
7266        CSSParserValue* stopArg = args->current();
7267        if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7268            stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
7269        else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
7270            stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
7271        else
7272            return false;
7273
7274        stopArg = args->next();
7275        if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
7276            return false;
7277
7278        stopArg = args->next();
7279        CSSValueID id = stopArg->id;
7280        if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
7281            stop.m_color = cssValuePool().createIdentifierValue(id);
7282        else
7283            stop.m_color = p->parseColor(stopArg);
7284        if (!stop.m_color)
7285            return false;
7286    }
7287
7288    return true;
7289}
7290
7291bool CSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient)
7292{
7293    // Walk the arguments.
7294    CSSParserValueList* args = valueList->current()->function->args.get();
7295    if (!args || args->size() == 0)
7296        return false;
7297
7298    // The first argument is the gradient type.  It is an identifier.
7299    CSSGradientType gradientType;
7300    CSSParserValue* a = args->current();
7301    if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
7302        return false;
7303    if (equalIgnoringCase(a, "linear"))
7304        gradientType = CSSDeprecatedLinearGradient;
7305    else if (equalIgnoringCase(a, "radial"))
7306        gradientType = CSSDeprecatedRadialGradient;
7307    else
7308        return false;
7309
7310    RefPtr<CSSGradientValue> result;
7311    switch (gradientType) {
7312    case CSSDeprecatedLinearGradient:
7313        result = CSSLinearGradientValue::create(NonRepeating, gradientType);
7314        break;
7315    case CSSDeprecatedRadialGradient:
7316        result = CSSRadialGradientValue::create(NonRepeating, gradientType);
7317        break;
7318    default:
7319        // The rest of the gradient types shouldn't appear here.
7320        ASSERT_NOT_REACHED();
7321    }
7322
7323    // Comma.
7324    a = args->next();
7325    if (!isComma(a))
7326        return false;
7327
7328    // Next comes the starting point for the gradient as an x y pair.  There is no
7329    // comma between the x and the y values.
7330    // First X.  It can be left, right, number or percent.
7331    a = args->next();
7332    if (!a)
7333        return false;
7334    RefPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
7335    if (!point)
7336        return false;
7337    result->setFirstX(point.release());
7338
7339    // First Y.  It can be top, bottom, number or percent.
7340    a = args->next();
7341    if (!a)
7342        return false;
7343    point = parseDeprecatedGradientPoint(a, false);
7344    if (!point)
7345        return false;
7346    result->setFirstY(point.release());
7347
7348    // Comma after the first point.
7349    a = args->next();
7350    if (!isComma(a))
7351        return false;
7352
7353    // For radial gradients only, we now expect a numeric radius.
7354    if (gradientType == CSSDeprecatedRadialGradient) {
7355        a = args->next();
7356        if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
7357            return false;
7358        toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
7359
7360        // Comma after the first radius.
7361        a = args->next();
7362        if (!isComma(a))
7363            return false;
7364    }
7365
7366    // Next is the ending point for the gradient as an x, y pair.
7367    // Second X.  It can be left, right, number or percent.
7368    a = args->next();
7369    if (!a)
7370        return false;
7371    point = parseDeprecatedGradientPoint(a, true);
7372    if (!point)
7373        return false;
7374    result->setSecondX(point.release());
7375
7376    // Second Y.  It can be top, bottom, number or percent.
7377    a = args->next();
7378    if (!a)
7379        return false;
7380    point = parseDeprecatedGradientPoint(a, false);
7381    if (!point)
7382        return false;
7383    result->setSecondY(point.release());
7384
7385    // For radial gradients only, we now expect the second radius.
7386    if (gradientType == CSSDeprecatedRadialGradient) {
7387        // Comma after the second point.
7388        a = args->next();
7389        if (!isComma(a))
7390            return false;
7391
7392        a = args->next();
7393        if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
7394            return false;
7395        toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
7396    }
7397
7398    // We now will accept any number of stops (0 or more).
7399    a = args->next();
7400    while (a) {
7401        // Look for the comma before the next stop.
7402        if (!isComma(a))
7403            return false;
7404
7405        // Now examine the stop itself.
7406        a = args->next();
7407        if (!a)
7408            return false;
7409
7410        // The function name needs to be one of "from", "to", or "color-stop."
7411        CSSGradientColorStop stop;
7412        if (!parseDeprecatedGradientColorStop(this, a, stop))
7413            return false;
7414        result->addStop(stop);
7415
7416        // Advance
7417        a = args->next();
7418    }
7419
7420    gradient = result.release();
7421    return true;
7422}
7423
7424static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
7425{
7426    if (a->unit != CSSPrimitiveValue::CSS_IDENT)
7427        return 0;
7428
7429    switch (a->id) {
7430        case CSSValueLeft:
7431        case CSSValueRight:
7432            isHorizontal = true;
7433            break;
7434        case CSSValueTop:
7435        case CSSValueBottom:
7436            isHorizontal = false;
7437            break;
7438        default:
7439            return 0;
7440    }
7441    return cssValuePool().createIdentifierValue(a->id);
7442}
7443
7444static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSParser* p, CSSParserValue* value)
7445{
7446    CSSValueID id = value->id;
7447    if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
7448        return cssValuePool().createIdentifierValue(id);
7449
7450    return p->parseColor(value);
7451}
7452
7453bool CSSParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7454{
7455    RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient);
7456
7457    // Walk the arguments.
7458    CSSParserValueList* args = valueList->current()->function->args.get();
7459    if (!args || !args->size())
7460        return false;
7461
7462    CSSParserValue* a = args->current();
7463    if (!a)
7464        return false;
7465
7466    bool expectComma = false;
7467    // Look for angle.
7468    if (validUnit(a, FAngle, HTMLStandardMode)) {
7469        result->setAngle(createPrimitiveNumericValue(a));
7470
7471        args->next();
7472        expectComma = true;
7473    } else {
7474        // Look one or two optional keywords that indicate a side or corner.
7475        RefPtr<CSSPrimitiveValue> startX, startY;
7476
7477        RefPtr<CSSPrimitiveValue> location;
7478        bool isHorizontal = false;
7479        if ((location = valueFromSideKeyword(a, isHorizontal))) {
7480            if (isHorizontal)
7481                startX = location;
7482            else
7483                startY = location;
7484
7485            if ((a = args->next())) {
7486                if ((location = valueFromSideKeyword(a, isHorizontal))) {
7487                    if (isHorizontal) {
7488                        if (startX)
7489                            return false;
7490                        startX = location;
7491                    } else {
7492                        if (startY)
7493                            return false;
7494                        startY = location;
7495                    }
7496
7497                    args->next();
7498                }
7499            }
7500
7501            expectComma = true;
7502        }
7503
7504        if (!startX && !startY)
7505            startY = cssValuePool().createIdentifierValue(CSSValueTop);
7506
7507        result->setFirstX(startX.release());
7508        result->setFirstY(startY.release());
7509    }
7510
7511    if (!parseGradientColorStops(args, result.get(), expectComma))
7512        return false;
7513
7514    if (!result->stopCount())
7515        return false;
7516
7517    gradient = result.release();
7518    return true;
7519}
7520
7521bool CSSParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7522{
7523    RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
7524
7525    // Walk the arguments.
7526    CSSParserValueList* args = valueList->current()->function->args.get();
7527    if (!args || !args->size())
7528        return false;
7529
7530    CSSParserValue* a = args->current();
7531    if (!a)
7532        return false;
7533
7534    bool expectComma = false;
7535
7536    // Optional background-position
7537    RefPtr<CSSValue> centerX;
7538    RefPtr<CSSValue> centerY;
7539    // parse2ValuesFillPosition advances the args next pointer.
7540    parse2ValuesFillPosition(args, centerX, centerY);
7541    a = args->current();
7542    if (!a)
7543        return false;
7544
7545    if (centerX || centerY) {
7546        // Comma
7547        if (!isComma(a))
7548            return false;
7549
7550        a = args->next();
7551        if (!a)
7552            return false;
7553    }
7554
7555    result->setFirstX(toCSSPrimitiveValue(centerX.get()));
7556    result->setSecondX(toCSSPrimitiveValue(centerX.get()));
7557    // CSS3 radial gradients always share the same start and end point.
7558    result->setFirstY(toCSSPrimitiveValue(centerY.get()));
7559    result->setSecondY(toCSSPrimitiveValue(centerY.get()));
7560
7561    RefPtr<CSSPrimitiveValue> shapeValue;
7562    RefPtr<CSSPrimitiveValue> sizeValue;
7563
7564    // Optional shape and/or size in any order.
7565    for (int i = 0; i < 2; ++i) {
7566        if (a->unit != CSSPrimitiveValue::CSS_IDENT)
7567            break;
7568
7569        bool foundValue = false;
7570        switch (a->id) {
7571        case CSSValueCircle:
7572        case CSSValueEllipse:
7573            shapeValue = cssValuePool().createIdentifierValue(a->id);
7574            foundValue = true;
7575            break;
7576        case CSSValueClosestSide:
7577        case CSSValueClosestCorner:
7578        case CSSValueFarthestSide:
7579        case CSSValueFarthestCorner:
7580        case CSSValueContain:
7581        case CSSValueCover:
7582            sizeValue = cssValuePool().createIdentifierValue(a->id);
7583            foundValue = true;
7584            break;
7585        default:
7586            break;
7587        }
7588
7589        if (foundValue) {
7590            a = args->next();
7591            if (!a)
7592                return false;
7593
7594            expectComma = true;
7595        }
7596    }
7597
7598    result->setShape(shapeValue);
7599    result->setSizingBehavior(sizeValue);
7600
7601    // Or, two lengths or percentages
7602    RefPtr<CSSPrimitiveValue> horizontalSize;
7603    RefPtr<CSSPrimitiveValue> verticalSize;
7604
7605    if (!shapeValue && !sizeValue) {
7606        if (validUnit(a, FLength | FPercent)) {
7607            horizontalSize = createPrimitiveNumericValue(a);
7608            a = args->next();
7609            if (!a)
7610                return false;
7611
7612            expectComma = true;
7613        }
7614
7615        if (validUnit(a, FLength | FPercent)) {
7616            verticalSize = createPrimitiveNumericValue(a);
7617
7618            a = args->next();
7619            if (!a)
7620                return false;
7621            expectComma = true;
7622        }
7623    }
7624
7625    // Must have neither or both.
7626    if (!horizontalSize != !verticalSize)
7627        return false;
7628
7629    result->setEndHorizontalSize(horizontalSize);
7630    result->setEndVerticalSize(verticalSize);
7631
7632    if (!parseGradientColorStops(args, result.get(), expectComma))
7633        return false;
7634
7635    gradient = result.release();
7636    return true;
7637}
7638
7639bool CSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7640{
7641    RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient);
7642
7643    CSSParserValueList* args = valueList->current()->function->args.get();
7644    if (!args || !args->size())
7645        return false;
7646
7647    CSSParserValue* a = args->current();
7648    if (!a)
7649        return false;
7650
7651    bool expectComma = false;
7652    // Look for angle.
7653    if (validUnit(a, FAngle, HTMLStandardMode)) {
7654        result->setAngle(createPrimitiveNumericValue(a));
7655
7656        args->next();
7657        expectComma = true;
7658    } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) {
7659        // to [ [left | right] || [top | bottom] ]
7660        a = args->next();
7661        if (!a)
7662            return false;
7663
7664        RefPtr<CSSPrimitiveValue> endX, endY;
7665        RefPtr<CSSPrimitiveValue> location;
7666        bool isHorizontal = false;
7667
7668        location = valueFromSideKeyword(a, isHorizontal);
7669        if (!location)
7670            return false;
7671
7672        if (isHorizontal)
7673            endX = location;
7674        else
7675            endY = location;
7676
7677        a = args->next();
7678        if (!a)
7679            return false;
7680
7681        location = valueFromSideKeyword(a, isHorizontal);
7682        if (location) {
7683            if (isHorizontal) {
7684                if (endX)
7685                    return false;
7686                endX = location;
7687            } else {
7688                if (endY)
7689                    return false;
7690                endY = location;
7691            }
7692
7693            args->next();
7694        }
7695
7696        expectComma = true;
7697        result->setFirstX(endX.release());
7698        result->setFirstY(endY.release());
7699    }
7700
7701    if (!parseGradientColorStops(args, result.get(), expectComma))
7702        return false;
7703
7704    if (!result->stopCount())
7705        return false;
7706
7707    gradient = result.release();
7708    return true;
7709}
7710
7711bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7712{
7713    RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
7714
7715    CSSParserValueList* args = valueList->current()->function->args.get();
7716    if (!args || !args->size())
7717        return false;
7718
7719    CSSParserValue* a = args->current();
7720    if (!a)
7721        return false;
7722
7723    bool expectComma = false;
7724
7725    RefPtr<CSSPrimitiveValue> shapeValue;
7726    RefPtr<CSSPrimitiveValue> sizeValue;
7727    RefPtr<CSSPrimitiveValue> horizontalSize;
7728    RefPtr<CSSPrimitiveValue> verticalSize;
7729
7730    // First part of grammar, the size/shape clause:
7731    // [ circle || <length> ] |
7732    // [ ellipse || [ <length> | <percentage> ]{2} ] |
7733    // [ [ circle | ellipse] || <size-keyword> ]
7734    for (int i = 0; i < 3; ++i) {
7735        if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
7736            bool badIdent = false;
7737            switch (a->id) {
7738            case CSSValueCircle:
7739            case CSSValueEllipse:
7740                if (shapeValue)
7741                    return false;
7742                shapeValue = cssValuePool().createIdentifierValue(a->id);
7743                break;
7744            case CSSValueClosestSide:
7745            case CSSValueClosestCorner:
7746            case CSSValueFarthestSide:
7747            case CSSValueFarthestCorner:
7748                if (sizeValue || horizontalSize)
7749                    return false;
7750                sizeValue = cssValuePool().createIdentifierValue(a->id);
7751                break;
7752            default:
7753                badIdent = true;
7754            }
7755
7756            if (badIdent)
7757                break;
7758
7759            a = args->next();
7760            if (!a)
7761                return false;
7762        } else if (validUnit(a, FLength | FPercent)) {
7763
7764            if (sizeValue || horizontalSize)
7765                return false;
7766            horizontalSize = createPrimitiveNumericValue(a);
7767
7768            a = args->next();
7769            if (!a)
7770                return false;
7771
7772            if (validUnit(a, FLength | FPercent)) {
7773                verticalSize = createPrimitiveNumericValue(a);
7774                ++i;
7775                a = args->next();
7776                if (!a)
7777                    return false;
7778            }
7779        } else
7780            break;
7781    }
7782
7783    // You can specify size as a keyword or a length/percentage, not both.
7784    if (sizeValue && horizontalSize)
7785        return false;
7786    // Circles must have 0 or 1 lengths.
7787    if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize)
7788        return false;
7789    // Ellipses must have 0 or 2 length/percentages.
7790    if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
7791        return false;
7792    // If there's only one size, it must be a length.
7793    if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
7794        return false;
7795
7796    result->setShape(shapeValue);
7797    result->setSizingBehavior(sizeValue);
7798    result->setEndHorizontalSize(horizontalSize);
7799    result->setEndVerticalSize(verticalSize);
7800
7801    // Second part of grammar, the center-position clause:
7802    // at <position>
7803    RefPtr<CSSValue> centerX;
7804    RefPtr<CSSValue> centerY;
7805    if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) {
7806        a = args->next();
7807        if (!a)
7808            return false;
7809
7810        parseFillPosition(args, centerX, centerY);
7811        if (!(centerX && centerY))
7812            return false;
7813
7814        a = args->current();
7815        if (!a)
7816            return false;
7817        result->setFirstX(toCSSPrimitiveValue(centerX.get()));
7818        result->setFirstY(toCSSPrimitiveValue(centerY.get()));
7819        // Right now, CSS radial gradients have the same start and end centers.
7820        result->setSecondX(toCSSPrimitiveValue(centerX.get()));
7821        result->setSecondY(toCSSPrimitiveValue(centerY.get()));
7822    }
7823
7824    if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
7825        expectComma = true;
7826
7827    if (!parseGradientColorStops(args, result.get(), expectComma))
7828        return false;
7829
7830    gradient = result.release();
7831    return true;
7832}
7833
7834bool CSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
7835{
7836    CSSParserValue* a = valueList->current();
7837
7838    // Now look for color stops.
7839    while (a) {
7840        // Look for the comma before the next stop.
7841        if (expectComma) {
7842            if (!isComma(a))
7843                return false;
7844
7845            a = valueList->next();
7846            if (!a)
7847                return false;
7848        }
7849
7850        // <color-stop> = <color> [ <percentage> | <length> ]?
7851        CSSGradientColorStop stop;
7852        stop.m_color = parseGradientColorOrKeyword(this, a);
7853        if (!stop.m_color)
7854            return false;
7855
7856        a = valueList->next();
7857        if (a) {
7858            if (validUnit(a, FLength | FPercent)) {
7859                stop.m_position = createPrimitiveNumericValue(a);
7860                a = valueList->next();
7861            }
7862        }
7863
7864        gradient->addStop(stop);
7865        expectComma = true;
7866    }
7867
7868    // Must have 2 or more stops to be valid.
7869    return gradient->stopCount() >= 2;
7870}
7871
7872bool CSSParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
7873{
7874    CSSParserValue* val = valueList->current();
7875
7876    if (val->unit != CSSParserValue::Function)
7877        return false;
7878
7879    if (equalIgnoringCase(val->function->name, "-webkit-gradient("))
7880        return parseDeprecatedGradient(valueList, value);
7881
7882    if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient("))
7883        return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
7884
7885    if (equalIgnoringCase(val->function->name, "linear-gradient("))
7886        return parseLinearGradient(valueList, value, NonRepeating);
7887
7888    if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient("))
7889        return parseDeprecatedLinearGradient(valueList, value, Repeating);
7890
7891    if (equalIgnoringCase(val->function->name, "repeating-linear-gradient("))
7892        return parseLinearGradient(valueList, value, Repeating);
7893
7894    if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient("))
7895        return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
7896
7897    if (equalIgnoringCase(val->function->name, "radial-gradient("))
7898        return parseRadialGradient(valueList, value, NonRepeating);
7899
7900    if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient("))
7901        return parseDeprecatedRadialGradient(valueList, value, Repeating);
7902
7903    if (equalIgnoringCase(val->function->name, "repeating-radial-gradient("))
7904        return parseRadialGradient(valueList, value, Repeating);
7905
7906    if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
7907        return parseCanvas(valueList, value);
7908
7909    if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
7910        return parseCrossfade(valueList, value);
7911
7912    return false;
7913}
7914
7915bool CSSParser::parseCrossfade(CSSParserValueList* valueList, RefPtr<CSSValue>& crossfade)
7916{
7917    RefPtr<CSSCrossfadeValue> result;
7918
7919    // Walk the arguments.
7920    CSSParserValueList* args = valueList->current()->function->args.get();
7921    if (!args || args->size() != 5)
7922        return false;
7923    CSSParserValue* a = args->current();
7924    RefPtr<CSSValue> fromImageValue;
7925    RefPtr<CSSValue> toImageValue;
7926
7927    // The first argument is the "from" image. It is a fill image.
7928    if (!a || !parseFillImage(args, fromImageValue))
7929        return false;
7930    a = args->next();
7931
7932    // Skip a comma
7933    if (!isComma(a))
7934        return false;
7935    a = args->next();
7936
7937    // The second argument is the "to" image. It is a fill image.
7938    if (!a || !parseFillImage(args, toImageValue))
7939        return false;
7940    a = args->next();
7941
7942    // Skip a comma
7943    if (!isComma(a))
7944        return false;
7945    a = args->next();
7946
7947    // The third argument is the crossfade value. It is a percentage or a fractional number.
7948    RefPtr<CSSPrimitiveValue> percentage;
7949    if (!a)
7950        return false;
7951
7952    if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7953        percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
7954    else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
7955        percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
7956    else
7957        return false;
7958
7959    result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
7960    result->setPercentage(percentage);
7961
7962    crossfade = result;
7963
7964    return true;
7965}
7966
7967bool CSSParser::parseCanvas(CSSParserValueList* valueList, RefPtr<CSSValue>& canvas)
7968{
7969    // Walk the arguments.
7970    CSSParserValueList* args = valueList->current()->function->args.get();
7971    if (!args || args->size() != 1)
7972        return false;
7973
7974    // The first argument is the canvas name.  It is an identifier.
7975    CSSParserValue* value = args->current();
7976    if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
7977        return false;
7978
7979    canvas = CSSCanvasValue::create(value->string);
7980    return true;
7981}
7982
7983PassRefPtr<CSSValue> CSSParser::parseImageSet(CSSParserValueList* valueList)
7984{
7985    CSSParserValue* function = valueList->current();
7986
7987    if (function->unit != CSSParserValue::Function)
7988        return 0;
7989
7990    CSSParserValueList* functionArgs = valueList->current()->function->args.get();
7991    if (!functionArgs || !functionArgs->size() || !functionArgs->current())
7992        return 0;
7993
7994    RefPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
7995
7996    CSSParserValue* arg = functionArgs->current();
7997    while (arg) {
7998        if (arg->unit != CSSPrimitiveValue::CSS_URI)
7999            return 0;
8000
8001        RefPtr<CSSImageValue> image = CSSImageValue::create(completeURL(arg->string));
8002        imageSet->append(image);
8003
8004        arg = functionArgs->next();
8005        if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
8006            return 0;
8007
8008        double imageScaleFactor = 0;
8009        const String& string = arg->string;
8010        unsigned length = string.length();
8011        if (!length)
8012            return 0;
8013        if (string.is8Bit()) {
8014            const LChar* start = string.characters8();
8015            parseDouble(start, start + length, 'x', imageScaleFactor);
8016        } else {
8017            const UChar* start = string.characters16();
8018            parseDouble(start, start + length, 'x', imageScaleFactor);
8019        }
8020        if (imageScaleFactor <= 0)
8021            return 0;
8022        imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER));
8023
8024        // If there are no more arguments, we're done.
8025        arg = functionArgs->next();
8026        if (!arg)
8027            break;
8028
8029        // If there are more arguments, they should be after a comma.
8030        if (!isComma(arg))
8031            return 0;
8032
8033        // Skip the comma and move on to the next argument.
8034        arg = functionArgs->next();
8035    }
8036
8037    return imageSet.release();
8038}
8039
8040class TransformOperationInfo {
8041public:
8042    TransformOperationInfo(const CSSParserString& name)
8043        : m_type(CSSTransformValue::UnknownTransformOperation)
8044        , m_argCount(1)
8045        , m_allowSingleArgument(false)
8046        , m_unit(CSSParser::FUnknown)
8047    {
8048        const UChar* characters;
8049        unsigned nameLength = name.length();
8050
8051        const unsigned longestNameLength = 12;
8052        UChar characterBuffer[longestNameLength];
8053        if (name.is8Bit()) {
8054            unsigned length = std::min(longestNameLength, nameLength);
8055            const LChar* characters8 = name.characters8();
8056            for (unsigned i = 0; i < length; ++i)
8057                characterBuffer[i] = characters8[i];
8058            characters = characterBuffer;
8059        } else
8060            characters = name.characters16();
8061
8062        SWITCH(characters, nameLength) {
8063            CASE("skew(") {
8064                m_unit = CSSParser::FAngle;
8065                m_type = CSSTransformValue::SkewTransformOperation;
8066                m_allowSingleArgument = true;
8067                m_argCount = 3;
8068            }
8069            CASE("scale(") {
8070                m_unit = CSSParser::FNumber;
8071                m_type = CSSTransformValue::ScaleTransformOperation;
8072                m_allowSingleArgument = true;
8073                m_argCount = 3;
8074            }
8075            CASE("skewx(") {
8076                m_unit = CSSParser::FAngle;
8077                m_type = CSSTransformValue::SkewXTransformOperation;
8078            }
8079            CASE("skewy(") {
8080                m_unit = CSSParser::FAngle;
8081                m_type = CSSTransformValue::SkewYTransformOperation;
8082            }
8083            CASE("matrix(") {
8084                m_unit = CSSParser::FNumber;
8085                m_type = CSSTransformValue::MatrixTransformOperation;
8086                m_argCount = 11;
8087            }
8088            CASE("rotate(") {
8089                m_unit = CSSParser::FAngle;
8090                m_type = CSSTransformValue::RotateTransformOperation;
8091            }
8092            CASE("scalex(") {
8093                m_unit = CSSParser::FNumber;
8094                m_type = CSSTransformValue::ScaleXTransformOperation;
8095            }
8096            CASE("scaley(") {
8097                m_unit = CSSParser::FNumber;
8098                m_type = CSSTransformValue::ScaleYTransformOperation;
8099            }
8100            CASE("scalez(") {
8101                m_unit = CSSParser::FNumber;
8102                m_type = CSSTransformValue::ScaleZTransformOperation;
8103            }
8104            CASE("scale3d(") {
8105                m_unit = CSSParser::FNumber;
8106                m_type = CSSTransformValue::Scale3DTransformOperation;
8107                m_argCount = 5;
8108            }
8109            CASE("rotatex(") {
8110                m_unit = CSSParser::FAngle;
8111                m_type = CSSTransformValue::RotateXTransformOperation;
8112            }
8113            CASE("rotatey(") {
8114                m_unit = CSSParser::FAngle;
8115                m_type = CSSTransformValue::RotateYTransformOperation;
8116            }
8117            CASE("rotatez(") {
8118                m_unit = CSSParser::FAngle;
8119                m_type = CSSTransformValue::RotateZTransformOperation;
8120            }
8121            CASE("matrix3d(") {
8122                m_unit = CSSParser::FNumber;
8123                m_type = CSSTransformValue::Matrix3DTransformOperation;
8124                m_argCount = 31;
8125            }
8126            CASE("rotate3d(") {
8127                m_unit = CSSParser::FNumber;
8128                m_type = CSSTransformValue::Rotate3DTransformOperation;
8129                m_argCount = 7;
8130            }
8131            CASE("translate(") {
8132                m_unit = CSSParser::FLength | CSSParser::FPercent;
8133                m_type = CSSTransformValue::TranslateTransformOperation;
8134                m_allowSingleArgument = true;
8135                m_argCount = 3;
8136            }
8137            CASE("translatex(") {
8138                m_unit = CSSParser::FLength | CSSParser::FPercent;
8139                m_type = CSSTransformValue::TranslateXTransformOperation;
8140            }
8141            CASE("translatey(") {
8142                m_unit = CSSParser::FLength | CSSParser::FPercent;
8143                m_type = CSSTransformValue::TranslateYTransformOperation;
8144            }
8145            CASE("translatez(") {
8146                m_unit = CSSParser::FLength | CSSParser::FPercent;
8147                m_type = CSSTransformValue::TranslateZTransformOperation;
8148            }
8149            CASE("perspective(") {
8150                m_unit = CSSParser::FNumber;
8151                m_type = CSSTransformValue::PerspectiveTransformOperation;
8152            }
8153            CASE("translate3d(") {
8154                m_unit = CSSParser::FLength | CSSParser::FPercent;
8155                m_type = CSSTransformValue::Translate3DTransformOperation;
8156                m_argCount = 5;
8157            }
8158        }
8159    }
8160
8161    CSSTransformValue::TransformOperationType type() const { return m_type; }
8162    unsigned argCount() const { return m_argCount; }
8163    CSSParser::Units unit() const { return m_unit; }
8164
8165    bool unknown() const { return m_type == CSSTransformValue::UnknownTransformOperation; }
8166    bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
8167
8168private:
8169    CSSTransformValue::TransformOperationType m_type;
8170    unsigned m_argCount;
8171    bool m_allowSingleArgument;
8172    CSSParser::Units m_unit;
8173};
8174
8175PassRefPtr<CSSValueList> CSSParser::parseTransform()
8176{
8177    if (!m_valueList)
8178        return 0;
8179
8180    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8181    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
8182        RefPtr<CSSValue> parsedTransformValue = parseTransformValue(value);
8183        if (!parsedTransformValue)
8184            return 0;
8185
8186        list->append(parsedTransformValue.release());
8187    }
8188
8189    return list.release();
8190}
8191
8192PassRefPtr<CSSValue> CSSParser::parseTransformValue(CSSParserValue *value)
8193{
8194    if (value->unit != CSSParserValue::Function || !value->function)
8195        return 0;
8196
8197    // Every primitive requires at least one argument.
8198    CSSParserValueList* args = value->function->args.get();
8199    if (!args)
8200        return 0;
8201
8202    // See if the specified primitive is one we understand.
8203    TransformOperationInfo info(value->function->name);
8204    if (info.unknown())
8205        return 0;
8206
8207    if (!info.hasCorrectArgCount(args->size()))
8208        return 0;
8209
8210    // The transform is a list of functional primitives that specify transform operations.
8211    // We collect a list of CSSTransformValues, where each value specifies a single operation.
8212
8213    // Create the new CSSTransformValue for this operation and add it to our list.
8214    RefPtr<CSSTransformValue> transformValue = CSSTransformValue::create(info.type());
8215
8216    // Snag our values.
8217    CSSParserValue* a = args->current();
8218    unsigned argNumber = 0;
8219    while (a) {
8220        CSSParser::Units unit = info.unit();
8221
8222        if (info.type() == CSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
8223            // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
8224            if (!validUnit(a, FAngle, HTMLStandardMode))
8225                return 0;
8226        } else if (info.type() == CSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
8227            // 3rd param of translate3d() cannot be a percentage
8228            if (!validUnit(a, FLength, HTMLStandardMode))
8229                return 0;
8230        } else if (info.type() == CSSTransformValue::TranslateZTransformOperation && !argNumber) {
8231            // 1st param of translateZ() cannot be a percentage
8232            if (!validUnit(a, FLength, HTMLStandardMode))
8233                return 0;
8234        } else if (info.type() == CSSTransformValue::PerspectiveTransformOperation && !argNumber) {
8235            // 1st param of perspective() must be a non-negative number (deprecated) or length.
8236            if (!validUnit(a, FNumber | FLength | FNonNeg, HTMLStandardMode))
8237                return 0;
8238        } else if (!validUnit(a, unit, HTMLStandardMode))
8239            return 0;
8240
8241        // Add the value to the current transform operation.
8242        transformValue->append(createPrimitiveNumericValue(a));
8243
8244        a = args->next();
8245        if (!a)
8246            break;
8247        if (a->unit != CSSParserValue::Operator || a->iValue != ',')
8248            return 0;
8249        a = args->next();
8250
8251        argNumber++;
8252    }
8253
8254    return transformValue.release();
8255}
8256
8257bool CSSParser::isBlendMode(CSSValueID valueID)
8258{
8259    return (valueID >= CSSValueMultiply && valueID <= CSSValueLuminosity)
8260        || valueID == CSSValueNormal
8261        || valueID == CSSValueOverlay;
8262}
8263
8264bool CSSParser::isCompositeOperator(CSSValueID valueID)
8265{
8266    // FIXME: Add CSSValueDestination and CSSValueLighter when the Compositing spec updates.
8267    return valueID >= CSSValueClear && valueID <= CSSValueXor;
8268}
8269
8270static void filterInfoForName(const CSSParserString& name, CSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
8271{
8272    if (equalIgnoringCase(name, "grayscale("))
8273        filterType = CSSFilterValue::GrayscaleFilterOperation;
8274    else if (equalIgnoringCase(name, "sepia("))
8275        filterType = CSSFilterValue::SepiaFilterOperation;
8276    else if (equalIgnoringCase(name, "saturate("))
8277        filterType = CSSFilterValue::SaturateFilterOperation;
8278    else if (equalIgnoringCase(name, "hue-rotate("))
8279        filterType = CSSFilterValue::HueRotateFilterOperation;
8280    else if (equalIgnoringCase(name, "invert("))
8281        filterType = CSSFilterValue::InvertFilterOperation;
8282    else if (equalIgnoringCase(name, "opacity("))
8283        filterType = CSSFilterValue::OpacityFilterOperation;
8284    else if (equalIgnoringCase(name, "brightness("))
8285        filterType = CSSFilterValue::BrightnessFilterOperation;
8286    else if (equalIgnoringCase(name, "contrast("))
8287        filterType = CSSFilterValue::ContrastFilterOperation;
8288    else if (equalIgnoringCase(name, "blur("))
8289        filterType = CSSFilterValue::BlurFilterOperation;
8290    else if (equalIgnoringCase(name, "drop-shadow(")) {
8291        filterType = CSSFilterValue::DropShadowFilterOperation;
8292        maximumArgumentCount = 4;  // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
8293    }
8294    else if (equalIgnoringCase(name, "custom("))
8295        filterType = CSSFilterValue::CustomFilterOperation;
8296}
8297
8298static bool acceptCommaOperator(CSSParserValueList* argsList)
8299{
8300    if (CSSParserValue* arg = argsList->current()) {
8301        if (!isComma(arg))
8302            return false;
8303        argsList->next();
8304    }
8305    return true;
8306}
8307
8308PassRefPtr<CSSArrayFunctionValue> CSSParser::parseCustomFilterArrayFunction(CSSParserValue* value)
8309{
8310    ASSERT(value->unit == CSSParserValue::Function && value->function);
8311
8312    if (!equalIgnoringCase(value->function->name, "array("))
8313        return 0;
8314
8315    CSSParserValueList* arrayArgsParserValueList = value->function->args.get();
8316    if (!arrayArgsParserValueList || !arrayArgsParserValueList->size())
8317        return 0;
8318
8319    // array() values are comma separated.
8320    RefPtr<CSSArrayFunctionValue> arrayFunction = CSSArrayFunctionValue::create();
8321    while (true) {
8322        // We parse pairs <Value, Comma> at each step.
8323        CSSParserValue* currentParserValue = arrayArgsParserValueList->current();
8324        if (!currentParserValue || !validUnit(currentParserValue, FNumber, HTMLStandardMode))
8325            return 0;
8326
8327        RefPtr<CSSValue> arrayValue = cssValuePool().createValue(currentParserValue->fValue, CSSPrimitiveValue::CSS_NUMBER);
8328        arrayFunction->append(arrayValue.release());
8329
8330        CSSParserValue* nextParserValue = arrayArgsParserValueList->next();
8331        if (!nextParserValue)
8332            break;
8333
8334        if (!isComma(nextParserValue))
8335            return 0;
8336
8337        arrayArgsParserValueList->next();
8338    }
8339
8340    return arrayFunction;
8341}
8342
8343PassRefPtr<CSSMixFunctionValue> CSSParser::parseMixFunction(CSSParserValue* value)
8344{
8345    ASSERT(value->unit == CSSParserValue::Function && value->function);
8346
8347    if (!equalIgnoringCase(value->function->name, "mix("))
8348        return 0;
8349
8350    CSSParserValueList* argsList = value->function->args.get();
8351    if (!argsList)
8352        return 0;
8353
8354    unsigned numArgs = argsList->size();
8355    if (numArgs < 1 || numArgs > 3)
8356        return 0;
8357
8358    RefPtr<CSSMixFunctionValue> mixFunction = CSSMixFunctionValue::create();
8359
8360    bool hasBlendMode = false;
8361    bool hasAlphaCompositing = false;
8362
8363    for (CSSParserValue* arg = argsList->current(); arg; arg = argsList->next()) {
8364        RefPtr<CSSValue> value;
8365
8366        unsigned argNumber = argsList->currentIndex();
8367        if (!argNumber) {
8368            if (arg->unit == CSSPrimitiveValue::CSS_URI) {
8369                KURL shaderURL = completeURL(arg->string);
8370                value = CSSShaderValue::create(shaderURL.string());
8371            }
8372        } else if (argNumber == 1 || argNumber == 2) {
8373            if (!hasBlendMode && isBlendMode(arg->id)) {
8374                hasBlendMode = true;
8375                value = cssValuePool().createIdentifierValue(arg->id);
8376            } else if (!hasAlphaCompositing && isCompositeOperator(arg->id)) {
8377                hasAlphaCompositing = true;
8378                value = cssValuePool().createIdentifierValue(arg->id);
8379            }
8380        }
8381
8382        if (!value)
8383            return 0;
8384
8385        mixFunction->append(value.release());
8386    }
8387
8388    return mixFunction;
8389}
8390
8391PassRefPtr<CSSValueList> CSSParser::parseCustomFilterParameters(CSSParserValueList* argsList)
8392{
8393    //
8394    // params:      [<param-def>[,<param-def>*]]
8395    // param-def:   <param-name>wsp<param-value>
8396    // param-name:  <ident>
8397    // param-value: true|false[wsp+true|false]{0-3} |
8398    //              <number>[wsp+<number>]{0-3} |
8399    //              <array> |
8400    //              <transform> |
8401    //              <texture(<uri>)>
8402    // array: 'array('<number>[wsp<number>]*')'
8403    // css-3d-transform: <transform-function>;[<transform-function>]*
8404    // transform:   <css-3d-transform> | <mat>
8405    // mat:         'mat2('<number>(,<number>){3}')' |
8406    //              'mat3('<number>(,<number>){8}')' |
8407    //              'mat4('<number>(,<number>){15}')' )
8408    //
8409
8410    RefPtr<CSSValueList> paramList = CSSValueList::createCommaSeparated();
8411
8412    while (CSSParserValue* arg = argsList->current()) {
8413        if (arg->unit != CSSPrimitiveValue::CSS_IDENT)
8414            return 0;
8415
8416        RefPtr<CSSValueList> parameter = CSSValueList::createSpaceSeparated();
8417        parameter->append(createPrimitiveStringValue(arg));
8418
8419        arg = argsList->next();
8420        if (!arg)
8421            return 0;
8422
8423        RefPtr<CSSValue> parameterValue;
8424
8425        if (arg->unit == CSSParserValue::Function && arg->function) {
8426            // FIXME: Implement parsing for the other parameter types.
8427            // textures: https://bugs.webkit.org/show_bug.cgi?id=71442
8428            // mat2, mat3, mat4: https://bugs.webkit.org/show_bug.cgi?id=71444
8429            if (equalIgnoringCase(arg->function->name, "array(")) {
8430                parameterValue = parseCustomFilterArrayFunction(arg);
8431                // This parsing step only consumes function arguments,
8432                // argsList is therefore moved forward explicitely.
8433                argsList->next();
8434            } else
8435                parameterValue = parseCustomFilterTransform(argsList);
8436        } else {
8437            RefPtr<CSSValueList> paramValueList = CSSValueList::createSpaceSeparated();
8438            arg = argsList->current();
8439            while (arg) {
8440                // If we hit a comma, it means that we finished this parameter's values.
8441                if (isComma(arg))
8442                    break;
8443                if (!validUnit(arg, FNumber, HTMLStandardMode))
8444                    return 0;
8445                paramValueList->append(cssValuePool().createValue(arg->fValue, CSSPrimitiveValue::CSS_NUMBER));
8446                arg = argsList->next();
8447            }
8448            if (!paramValueList->length() || paramValueList->length() > 4)
8449                return 0;
8450            parameterValue = paramValueList.release();
8451        }
8452
8453        if (!parameterValue || !acceptCommaOperator(argsList))
8454            return 0;
8455
8456        parameter->append(parameterValue.release());
8457        paramList->append(parameter.release());
8458    }
8459
8460    return paramList;
8461}
8462
8463PassRefPtr<CSSFilterValue> CSSParser::parseCustomFilterFunctionWithAtRuleReferenceSyntax(CSSParserValue* value)
8464{
8465    //
8466    // Custom filter function "at-rule reference" syntax:
8467    //
8468    // custom(<filter-name>wsp[,wsp<params>])
8469    //
8470    // filter-name: <filter-name>
8471    // params: See the comment in CSSParser::parseCustomFilterParameters.
8472    //
8473
8474    ASSERT(value->function);
8475
8476    CSSParserValueList* argsList = value->function->args.get();
8477    if (!argsList || !argsList->size())
8478        return 0;
8479
8480    // 1. Parse the filter name.
8481    CSSParserValue* arg = argsList->current();
8482    if (arg->unit != CSSPrimitiveValue::CSS_IDENT)
8483        return 0;
8484
8485    RefPtr<CSSFilterValue> filterValue = CSSFilterValue::create(CSSFilterValue::CustomFilterOperation);
8486
8487    RefPtr<CSSValue> filterName = createPrimitiveStringValue(arg);
8488    filterValue->append(filterName);
8489    argsList->next();
8490
8491    if (!acceptCommaOperator(argsList))
8492        return 0;
8493
8494    // 2. Parse the parameters.
8495    RefPtr<CSSValueList> paramList = parseCustomFilterParameters(argsList);
8496    if (!paramList)
8497        return 0;
8498
8499    if (paramList->length())
8500        filterValue->append(paramList.release());
8501
8502    return filterValue;
8503}
8504
8505// FIXME: The custom filters "inline" syntax is deprecated. We will remove it eventually.
8506PassRefPtr<CSSFilterValue> CSSParser::parseCustomFilterFunctionWithInlineSyntax(CSSParserValue* value)
8507{
8508    //
8509    // Custom filter function "inline" syntax:
8510    //
8511    // custom(<vertex-shader>[wsp<fragment-shader>][,<vertex-mesh>][,<params>])
8512    //
8513    // vertexShader:    <uri> | none
8514    // fragmentShader:  <uri> | none | mix(<uri> [ <blend-mode> || <alpha-compositing> ]?)
8515    //
8516    // blend-mode: normal | multiply | screen | overlay | darken | lighten | color-dodge |
8517    //             color-burn | hard-light | soft-light | difference | exclusion | hue |
8518    //             saturation | color | luminosity
8519    // alpha-compositing: clear | src | dst | src-over | dst-over | src-in | dst-in |
8520    //                    src-out | dst-out | src-atop | dst-atop | xor | plus
8521    //
8522    // vertexMesh:  +<integer>{1,2}[wsp<box>][wsp'detached']
8523    // box: filter-box | border-box | padding-box | content-box
8524    //
8525    // params: See the comment in CSSParser::parseCustomFilterParameters.
8526    //
8527
8528    ASSERT(value->function);
8529
8530    CSSParserValueList* argsList = value->function->args.get();
8531    if (!argsList)
8532        return 0;
8533
8534    RefPtr<CSSFilterValue> filterValue = CSSFilterValue::create(CSSFilterValue::CustomFilterOperation);
8535
8536    // 1. Parse the shader URLs: <vertex-shader>[wsp<fragment-shader>]
8537    RefPtr<CSSValueList> shadersList = CSSValueList::createSpaceSeparated();
8538    bool hadAtLeastOneCustomShader = false;
8539    CSSParserValue* arg;
8540    for (arg = argsList->current(); arg; arg = argsList->next()) {
8541        RefPtr<CSSValue> value;
8542        if (arg->id == CSSValueNone)
8543            value = cssValuePool().createIdentifierValue(CSSValueNone);
8544        else if (arg->unit == CSSPrimitiveValue::CSS_URI) {
8545            KURL shaderURL = completeURL(arg->string);
8546            value = CSSShaderValue::create(shaderURL.string());
8547            hadAtLeastOneCustomShader = true;
8548        } else if (argsList->currentIndex() == 1 && arg->unit == CSSParserValue::Function) {
8549            if (!(value = parseMixFunction(arg)))
8550                return 0;
8551            hadAtLeastOneCustomShader = true;
8552        }
8553
8554        if (!value)
8555            break;
8556        shadersList->append(value.release());
8557    }
8558
8559    if (!shadersList->length() || !hadAtLeastOneCustomShader || shadersList->length() > 2 || !acceptCommaOperator(argsList))
8560        return 0;
8561
8562    filterValue->append(shadersList.release());
8563
8564    // 2. Parse the mesh size <vertex-mesh>
8565    RefPtr<CSSValueList> meshSizeList = CSSValueList::createSpaceSeparated();
8566
8567    for (arg = argsList->current(); arg; arg = argsList->next()) {
8568        if (!validUnit(arg, FInteger | FNonNeg, HTMLStandardMode))
8569            break;
8570        int integerValue = clampToInteger(arg->fValue);
8571        // According to the specification we can only accept positive non-zero values.
8572        if (integerValue < 1)
8573            return 0;
8574        meshSizeList->append(cssValuePool().createValue(integerValue, CSSPrimitiveValue::CSS_NUMBER));
8575    }
8576
8577    if (meshSizeList->length() > 2)
8578        return 0;
8579
8580    // FIXME: For legacy content, we accept the mesh box types. We don't do anything else with them.
8581    // Eventually, we'll remove them completely.
8582    // https://bugs.webkit.org/show_bug.cgi?id=103778
8583    if ((arg = argsList->current()) && (arg->id == CSSValueBorderBox || arg->id == CSSValuePaddingBox
8584        || arg->id == CSSValueContentBox || arg->id == CSSValueFilterBox))
8585        argsList->next();
8586
8587    if ((arg = argsList->current()) && arg->id == CSSValueDetached) {
8588        meshSizeList->append(cssValuePool().createIdentifierValue(arg->id));
8589        argsList->next();
8590    }
8591
8592    if (meshSizeList->length()) {
8593        if (!acceptCommaOperator(argsList))
8594            return 0;
8595        filterValue->append(meshSizeList.release());
8596    }
8597
8598    // 3. Parse the parameters.
8599    RefPtr<CSSValueList> paramList = parseCustomFilterParameters(argsList);
8600    if (!paramList)
8601        return 0;
8602
8603    if (paramList->length())
8604        filterValue->append(paramList.release());
8605
8606    return filterValue;
8607}
8608
8609PassRefPtr<CSSFilterValue> CSSParser::parseCustomFilterFunction(CSSParserValue* value)
8610{
8611    ASSERT(value->function);
8612
8613    // Look ahead to determine which syntax the custom function is using.
8614    // Both the at-rule reference syntax and the inline syntax require at least one argument.
8615    CSSParserValueList* argsList = value->function->args.get();
8616    if (!argsList || !argsList->size())
8617        return 0;
8618
8619    // The at-rule reference syntax expects a single ident or an ident followed by a comma.
8620    // e.g. custom(my-filter) or custom(my-filter, ...)
8621    // In contrast, when the inline syntax starts with an ident like "none", it expects a uri or a mix function next.
8622    // e.g. custom(none url(...)) or custom(none mix(...)
8623    bool isAtRuleReferenceSyntax = argsList->valueAt(0)->unit == CSSPrimitiveValue::CSS_IDENT
8624        && (argsList->size() == 1 || isComma(argsList->valueAt(1)));
8625    return isAtRuleReferenceSyntax ? parseCustomFilterFunctionWithAtRuleReferenceSyntax(value) : parseCustomFilterFunctionWithInlineSyntax(value);
8626}
8627
8628PassRefPtr<CSSValueList> CSSParser::parseCustomFilterTransform(CSSParserValueList* valueList)
8629{
8630    if (!valueList)
8631        return 0;
8632
8633    // CSS Shaders' custom() transforms are space separated and comma terminated.
8634    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8635    for (CSSParserValue* value = valueList->current(); value; value = valueList->next()) {
8636        if (isComma(value))
8637            break;
8638
8639        RefPtr<CSSValue> parsedTransformValue = parseTransformValue(value);
8640        if (!parsedTransformValue)
8641            return 0;
8642
8643        list->append(parsedTransformValue.release());
8644    }
8645
8646    return list.release();
8647}
8648
8649PassRefPtr<CSSShaderValue> CSSParser::parseFilterRuleSrcUriAndFormat(CSSParserValueList* valueList)
8650{
8651    CSSParserValue* value = valueList->current();
8652    ASSERT(value && value->unit == CSSPrimitiveValue::CSS_URI);
8653    RefPtr<CSSShaderValue> shaderValue = CSSShaderValue::create(completeURL(value->string));
8654
8655    value = valueList->next();
8656    if (value && value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "format(")) {
8657        CSSParserValueList* args = value->function->args.get();
8658        if (!args || args->size() != 1)
8659            return 0;
8660
8661        CSSParserValue* arg = args->current();
8662        if (arg->unit != CSSPrimitiveValue::CSS_STRING)
8663            return 0;
8664
8665        shaderValue->setFormat(arg->string);
8666        valueList->next();
8667    }
8668
8669    return shaderValue.release();
8670}
8671
8672bool CSSParser::parseFilterRuleSrc()
8673{
8674    RefPtr<CSSValueList> srcList = CSSValueList::createCommaSeparated();
8675
8676    CSSParserValue* value = m_valueList->current();
8677    while (value) {
8678        if (value->unit != CSSPrimitiveValue::CSS_URI)
8679            return false;
8680
8681        RefPtr<CSSShaderValue> shaderValue = parseFilterRuleSrcUriAndFormat(m_valueList.get());
8682        if (!shaderValue)
8683            return false;
8684        srcList->append(shaderValue.release());
8685
8686        if (!acceptCommaOperator(m_valueList.get()))
8687            return false;
8688
8689        value = m_valueList->current();
8690    }
8691
8692    if (!srcList->length())
8693        return false;
8694
8695    addProperty(CSSPropertySrc, srcList.release(), m_important);
8696    return true;
8697}
8698
8699StyleRuleBase* CSSParser::createFilterRule(const CSSParserString& filterName)
8700{
8701    RefPtr<StyleRuleFilter> rule = StyleRuleFilter::create(filterName);
8702    rule->setProperties(createStylePropertySet());
8703    clearProperties();
8704    StyleRuleFilter* result = rule.get();
8705    m_parsedRules.append(rule.release());
8706    return result;
8707}
8708
8709
8710PassRefPtr<CSSFilterValue> CSSParser::parseBuiltinFilterArguments(CSSParserValueList* args, CSSFilterValue::FilterOperationType filterType)
8711{
8712    RefPtr<CSSFilterValue> filterValue = CSSFilterValue::create(filterType);
8713    ASSERT(args);
8714
8715    switch (filterType) {
8716    case CSSFilterValue::GrayscaleFilterOperation:
8717    case CSSFilterValue::SepiaFilterOperation:
8718    case CSSFilterValue::SaturateFilterOperation:
8719    case CSSFilterValue::InvertFilterOperation:
8720    case CSSFilterValue::OpacityFilterOperation:
8721    case CSSFilterValue::ContrastFilterOperation: {
8722        // One optional argument, 0-1 or 0%-100%, if missing use 100%.
8723        if (args->size() > 1)
8724            return 0;
8725
8726        if (args->size()) {
8727            CSSParserValue* value = args->current();
8728            if (!validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode))
8729                return 0;
8730
8731            double amount = value->fValue;
8732
8733            // Saturate and Contrast allow values over 100%.
8734            if (filterType != CSSFilterValue::SaturateFilterOperation
8735                && filterType != CSSFilterValue::ContrastFilterOperation) {
8736                double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
8737                if (amount > maxAllowed)
8738                    return 0;
8739            }
8740
8741            filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
8742        }
8743        break;
8744    }
8745    case CSSFilterValue::BrightnessFilterOperation: {
8746        // One optional argument, if missing use 100%.
8747        if (args->size() > 1)
8748            return 0;
8749
8750        if (args->size()) {
8751            CSSParserValue* value = args->current();
8752            if (!validUnit(value, FNumber | FPercent, HTMLStandardMode))
8753                return 0;
8754
8755            filterValue->append(cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
8756        }
8757        break;
8758    }
8759    case CSSFilterValue::HueRotateFilterOperation: {
8760        // hue-rotate() takes one optional angle.
8761        if (args->size() > 1)
8762            return 0;
8763
8764        if (args->size()) {
8765            CSSParserValue* argument = args->current();
8766            if (!validUnit(argument, FAngle, HTMLStandardMode))
8767                return 0;
8768
8769            filterValue->append(createPrimitiveNumericValue(argument));
8770        }
8771        break;
8772    }
8773    case CSSFilterValue::BlurFilterOperation: {
8774        // Blur takes a single length. Zero parameters are allowed.
8775        if (args->size() > 1)
8776            return 0;
8777
8778        if (args->size()) {
8779            CSSParserValue* argument = args->current();
8780            if (!validUnit(argument, FLength | FNonNeg, HTMLStandardMode))
8781                return 0;
8782
8783            filterValue->append(createPrimitiveNumericValue(argument));
8784        }
8785        break;
8786    }
8787    case CSSFilterValue::DropShadowFilterOperation: {
8788        // drop-shadow() takes a single shadow.
8789        RefPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter);
8790        if (!shadowValueList || shadowValueList->length() != 1)
8791            return 0;
8792
8793        filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0));
8794        break;
8795    }
8796    default:
8797        ASSERT_NOT_REACHED();
8798    }
8799    return filterValue.release();
8800}
8801
8802PassRefPtr<CSSValueList> CSSParser::parseFilter()
8803{
8804    if (!m_valueList)
8805        return 0;
8806
8807    // The filter is a list of functional primitives that specify individual operations.
8808    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8809    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
8810        if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function))
8811            return 0;
8812
8813        CSSFilterValue::FilterOperationType filterType = CSSFilterValue::UnknownFilterOperation;
8814
8815        // See if the specified primitive is one we understand.
8816        if (value->unit == CSSPrimitiveValue::CSS_URI) {
8817            RefPtr<CSSFilterValue> referenceFilterValue = CSSFilterValue::create(CSSFilterValue::ReferenceFilterOperation);
8818            list->append(referenceFilterValue);
8819            referenceFilterValue->append(CSSSVGDocumentValue::create(value->string));
8820        } else {
8821            const CSSParserString name = value->function->name;
8822            unsigned maximumArgumentCount = 1;
8823
8824            filterInfoForName(name, filterType, maximumArgumentCount);
8825
8826            if (filterType == CSSFilterValue::UnknownFilterOperation)
8827                return 0;
8828
8829            if (filterType == CSSFilterValue::CustomFilterOperation) {
8830                // Make sure parsing fails if custom filters are disabled.
8831                if (!RuntimeEnabledFeatures::cssCustomFilterEnabled())
8832                    return 0;
8833
8834                RefPtr<CSSFilterValue> filterValue = parseCustomFilterFunction(value);
8835                if (!filterValue)
8836                    return 0;
8837                list->append(filterValue.release());
8838                continue;
8839            }
8840            CSSParserValueList* args = value->function->args.get();
8841            if (!args)
8842                return 0;
8843
8844            RefPtr<CSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType);
8845            if (!filterValue)
8846                return 0;
8847
8848            list->append(filterValue);
8849        }
8850    }
8851
8852    return list.release();
8853}
8854
8855static bool validFlowName(const String& flowName)
8856{
8857    return !(equalIgnoringCase(flowName, "auto")
8858            || equalIgnoringCase(flowName, "default")
8859            || equalIgnoringCase(flowName, "inherit")
8860            || equalIgnoringCase(flowName, "initial")
8861            || equalIgnoringCase(flowName, "none"));
8862}
8863
8864bool CSSParser::parseFlowThread(const String& flowName)
8865{
8866    setupParser("@-internal-decls -webkit-flow-into:", flowName, "");
8867    cssyyparse(this);
8868
8869    m_rule = 0;
8870
8871    return ((m_parsedProperties.size() == 1) && (m_parsedProperties.first().id() == CSSPropertyWebkitFlowInto));
8872}
8873
8874// none | <ident>
8875bool CSSParser::parseFlowThread(CSSPropertyID propId, bool important)
8876{
8877    ASSERT(propId == CSSPropertyWebkitFlowInto);
8878    ASSERT(RuntimeEnabledFeatures::cssRegionsEnabled());
8879
8880    if (m_valueList->size() != 1)
8881        return false;
8882
8883    CSSParserValue* value = m_valueList->current();
8884    if (!value)
8885        return false;
8886
8887    if (value->unit != CSSPrimitiveValue::CSS_IDENT)
8888        return false;
8889
8890    if (value->id == CSSValueNone) {
8891        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
8892        return true;
8893    }
8894
8895    String inputProperty = String(value->string);
8896    if (!inputProperty.isEmpty()) {
8897        if (!validFlowName(inputProperty))
8898            return false;
8899        addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
8900    } else
8901        addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
8902
8903    return true;
8904}
8905
8906// -webkit-flow-from: none | <ident>
8907bool CSSParser::parseRegionThread(CSSPropertyID propId, bool important)
8908{
8909    ASSERT(propId == CSSPropertyWebkitFlowFrom);
8910    ASSERT(RuntimeEnabledFeatures::cssRegionsEnabled());
8911
8912    if (m_valueList->size() != 1)
8913        return false;
8914
8915    CSSParserValue* value = m_valueList->current();
8916    if (!value)
8917        return false;
8918
8919    if (value->unit != CSSPrimitiveValue::CSS_IDENT)
8920        return false;
8921
8922    if (value->id == CSSValueNone)
8923        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
8924    else {
8925        String inputProperty = String(value->string);
8926        if (!inputProperty.isEmpty()) {
8927            if (!validFlowName(inputProperty))
8928                return false;
8929            addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
8930        } else
8931            addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
8932    }
8933
8934    return true;
8935}
8936
8937bool CSSParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
8938{
8939    propId1 = propId;
8940    propId2 = propId;
8941    propId3 = propId;
8942    if (propId == CSSPropertyWebkitTransformOrigin) {
8943        propId1 = CSSPropertyWebkitTransformOriginX;
8944        propId2 = CSSPropertyWebkitTransformOriginY;
8945        propId3 = CSSPropertyWebkitTransformOriginZ;
8946    }
8947
8948    switch (propId) {
8949        case CSSPropertyWebkitTransformOrigin:
8950            if (!parseTransformOriginShorthand(value, value2, value3))
8951                return false;
8952            // parseTransformOriginShorthand advances the m_valueList pointer
8953            break;
8954        case CSSPropertyWebkitTransformOriginX: {
8955            value = parseFillPositionX(m_valueList.get());
8956            if (value)
8957                m_valueList->next();
8958            break;
8959        }
8960        case CSSPropertyWebkitTransformOriginY: {
8961            value = parseFillPositionY(m_valueList.get());
8962            if (value)
8963                m_valueList->next();
8964            break;
8965        }
8966        case CSSPropertyWebkitTransformOriginZ: {
8967            if (validUnit(m_valueList->current(), FLength))
8968                value = createPrimitiveNumericValue(m_valueList->current());
8969            if (value)
8970                m_valueList->next();
8971            break;
8972        }
8973        default:
8974            ASSERT_NOT_REACHED();
8975            return false;
8976    }
8977
8978    return value;
8979}
8980
8981bool CSSParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2)
8982{
8983    propId1 = propId;
8984    propId2 = propId;
8985    if (propId == CSSPropertyWebkitPerspectiveOrigin) {
8986        propId1 = CSSPropertyWebkitPerspectiveOriginX;
8987        propId2 = CSSPropertyWebkitPerspectiveOriginY;
8988    }
8989
8990    switch (propId) {
8991        case CSSPropertyWebkitPerspectiveOrigin:
8992            if (m_valueList->size() > 2)
8993                return false;
8994            parse2ValuesFillPosition(m_valueList.get(), value, value2);
8995            break;
8996        case CSSPropertyWebkitPerspectiveOriginX: {
8997            value = parseFillPositionX(m_valueList.get());
8998            if (value)
8999                m_valueList->next();
9000            break;
9001        }
9002        case CSSPropertyWebkitPerspectiveOriginY: {
9003            value = parseFillPositionY(m_valueList.get());
9004            if (value)
9005                m_valueList->next();
9006            break;
9007        }
9008        default:
9009            ASSERT_NOT_REACHED();
9010            return false;
9011    }
9012
9013    return value;
9014}
9015
9016bool CSSParser::parseTouchAction(bool important)
9017{
9018    if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
9019        return false;
9020
9021    CSSParserValue* value = m_valueList->current();
9022    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9023    if (m_valueList->size() == 1 && value && (value->id == CSSValueAuto || value->id == CSSValueNone)) {
9024        list->append(cssValuePool().createIdentifierValue(value->id));
9025        addProperty(CSSPropertyTouchAction, list.release(), important);
9026        m_valueList->next();
9027        return true;
9028    }
9029
9030    bool isValid = true;
9031    while (isValid && value) {
9032        switch (value->id) {
9033        case CSSValuePanX:
9034        case CSSValuePanY: {
9035            RefPtr<CSSValue> panValue = cssValuePool().createIdentifierValue(value->id);
9036            if (list->hasValue(panValue.get())) {
9037                isValid = false;
9038                break;
9039            }
9040            list->append(panValue.release());
9041            break;
9042        }
9043        default:
9044            isValid = false;
9045            break;
9046        }
9047        if (isValid)
9048            value = m_valueList->next();
9049    }
9050
9051    if (list->length() && isValid) {
9052        addProperty(CSSPropertyTouchAction, list.release(), important);
9053        return true;
9054    }
9055
9056    return false;
9057}
9058
9059void CSSParser::addTextDecorationProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important)
9060{
9061    // The text-decoration-line property takes priority over text-decoration, unless the latter has important priority set.
9062    if (propId == CSSPropertyTextDecoration && !important && !inShorthand()) {
9063        for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
9064            if (m_parsedProperties[i].id() == CSSPropertyTextDecorationLine)
9065                return;
9066        }
9067    }
9068    addProperty(propId, value, important);
9069}
9070
9071bool CSSParser::parseTextDecoration(CSSPropertyID propId, bool important)
9072{
9073    if (propId == CSSPropertyTextDecorationLine
9074        && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
9075        return false;
9076
9077    CSSParserValue* value = m_valueList->current();
9078    if (value && value->id == CSSValueNone) {
9079        addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
9080        m_valueList->next();
9081        return true;
9082    }
9083
9084    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9085    bool isValid = true;
9086    while (isValid && value) {
9087        switch (value->id) {
9088        case CSSValueUnderline:
9089        case CSSValueOverline:
9090        case CSSValueLineThrough:
9091        case CSSValueBlink:
9092            list->append(cssValuePool().createIdentifierValue(value->id));
9093            break;
9094        default:
9095            isValid = false;
9096            break;
9097        }
9098        if (isValid)
9099            value = m_valueList->next();
9100    }
9101
9102    // Values are either valid or in shorthand scope.
9103    if (list->length() && (isValid || inShorthand())) {
9104        addTextDecorationProperty(propId, list.release(), important);
9105        return true;
9106    }
9107
9108    return false;
9109}
9110
9111bool CSSParser::parseTextUnderlinePosition(bool important)
9112{
9113    // The text-underline-position property has syntax "auto | [ under || [ left | right ] ]".
9114    // However, values 'left' and 'right' are not implemented yet, so we will parse syntax
9115    // "auto | under" for now.
9116    CSSParserValue* value = m_valueList->current();
9117    switch (value->id) {
9118    case CSSValueAuto:
9119    case CSSValueUnder:
9120        if (m_valueList->next())
9121            return false;
9122        addProperty(CSSPropertyTextUnderlinePosition, cssValuePool().createIdentifierValue(value->id), important);
9123        return true;
9124    default:
9125        return false;
9126    }
9127}
9128
9129bool CSSParser::parseTextEmphasisStyle(bool important)
9130{
9131    unsigned valueListSize = m_valueList->size();
9132
9133    RefPtr<CSSPrimitiveValue> fill;
9134    RefPtr<CSSPrimitiveValue> shape;
9135
9136    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9137        if (value->unit == CSSPrimitiveValue::CSS_STRING) {
9138            if (fill || shape || (valueListSize != 1 && !inShorthand()))
9139                return false;
9140            addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important);
9141            m_valueList->next();
9142            return true;
9143        }
9144
9145        if (value->id == CSSValueNone) {
9146            if (fill || shape || (valueListSize != 1 && !inShorthand()))
9147                return false;
9148            addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important);
9149            m_valueList->next();
9150            return true;
9151        }
9152
9153        if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
9154            if (fill)
9155                return false;
9156            fill = cssValuePool().createIdentifierValue(value->id);
9157        } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
9158            if (shape)
9159                return false;
9160            shape = cssValuePool().createIdentifierValue(value->id);
9161        } else if (!inShorthand())
9162            return false;
9163        else
9164            break;
9165    }
9166
9167    if (fill && shape) {
9168        RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
9169        parsedValues->append(fill.release());
9170        parsedValues->append(shape.release());
9171        addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
9172        return true;
9173    }
9174    if (fill) {
9175        addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
9176        return true;
9177    }
9178    if (shape) {
9179        addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
9180        return true;
9181    }
9182
9183    return false;
9184}
9185
9186PassRefPtr<CSSValue> CSSParser::parseTextIndent()
9187{
9188    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9189
9190    // <length> | <percentage> | inherit
9191    if (m_valueList->size() == 1) {
9192        CSSParserValue* value = m_valueList->current();
9193        if (!value->id && validUnit(value, FLength | FPercent)) {
9194            list->append(createPrimitiveNumericValue(value));
9195            m_valueList->next();
9196            return list.release();
9197        }
9198    }
9199
9200    if (!RuntimeEnabledFeatures::css3TextEnabled())
9201        return 0;
9202
9203    // The case where text-indent has only <length>(or <percentage>) value
9204    // is handled above if statement even though css3TextEnabled() returns true.
9205
9206    // [ [ <length> | <percentage> ] && each-line ] | inherit
9207    if (m_valueList->size() != 2)
9208        return 0;
9209
9210    CSSParserValue* firstValue = m_valueList->current();
9211    CSSParserValue* secondValue = m_valueList->next();
9212    CSSParserValue* lengthOrPercentageValue = 0;
9213
9214    // [ <length> | <percentage> ] each-line
9215    if (validUnit(firstValue, FLength | FPercent) && secondValue->id == CSSValueEachLine)
9216        lengthOrPercentageValue = firstValue;
9217    // each-line [ <length> | <percentage> ]
9218    else if (firstValue->id == CSSValueEachLine && validUnit(secondValue, FLength | FPercent))
9219        lengthOrPercentageValue = secondValue;
9220
9221    if (lengthOrPercentageValue) {
9222        list->append(createPrimitiveNumericValue(lengthOrPercentageValue));
9223        list->append(cssValuePool().createIdentifierValue(CSSValueEachLine));
9224        m_valueList->next();
9225        return list.release();
9226    }
9227
9228    return 0;
9229}
9230
9231bool CSSParser::parseLineBoxContain(bool important)
9232{
9233    LineBoxContain lineBoxContain = LineBoxContainNone;
9234
9235    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9236        if (value->id == CSSValueBlock) {
9237            if (lineBoxContain & LineBoxContainBlock)
9238                return false;
9239            lineBoxContain |= LineBoxContainBlock;
9240        } else if (value->id == CSSValueInline) {
9241            if (lineBoxContain & LineBoxContainInline)
9242                return false;
9243            lineBoxContain |= LineBoxContainInline;
9244        } else if (value->id == CSSValueFont) {
9245            if (lineBoxContain & LineBoxContainFont)
9246                return false;
9247            lineBoxContain |= LineBoxContainFont;
9248        } else if (value->id == CSSValueGlyphs) {
9249            if (lineBoxContain & LineBoxContainGlyphs)
9250                return false;
9251            lineBoxContain |= LineBoxContainGlyphs;
9252        } else if (value->id == CSSValueReplaced) {
9253            if (lineBoxContain & LineBoxContainReplaced)
9254                return false;
9255            lineBoxContain |= LineBoxContainReplaced;
9256        } else if (value->id == CSSValueInlineBox) {
9257            if (lineBoxContain & LineBoxContainInlineBox)
9258                return false;
9259            lineBoxContain |= LineBoxContainInlineBox;
9260        } else
9261            return false;
9262    }
9263
9264    if (!lineBoxContain)
9265        return false;
9266
9267    addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
9268    return true;
9269}
9270
9271bool CSSParser::parseFontFeatureTag(CSSValueList* settings)
9272{
9273    // Feature tag name consists of 4-letter characters.
9274    static const unsigned tagNameLength = 4;
9275
9276    CSSParserValue* value = m_valueList->current();
9277    // Feature tag name comes first
9278    if (value->unit != CSSPrimitiveValue::CSS_STRING)
9279        return false;
9280    if (value->string.length() != tagNameLength)
9281        return false;
9282    for (unsigned i = 0; i < tagNameLength; ++i) {
9283        // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
9284        UChar character = value->string[i];
9285        if (character < 0x20 || character > 0x7E)
9286            return false;
9287    }
9288
9289    AtomicString tag = value->string;
9290    int tagValue = 1;
9291    // Feature tag values could follow: <integer> | on | off
9292    value = m_valueList->next();
9293    if (value) {
9294        if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
9295            tagValue = clampToInteger(value->fValue);
9296            if (tagValue < 0)
9297                return false;
9298            m_valueList->next();
9299        } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
9300            tagValue = value->id == CSSValueOn;
9301            m_valueList->next();
9302        }
9303    }
9304    settings->append(CSSFontFeatureValue::create(tag, tagValue));
9305    return true;
9306}
9307
9308bool CSSParser::parseFontFeatureSettings(bool important)
9309{
9310    if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) {
9311        RefPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal);
9312        m_valueList->next();
9313        addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
9314        return true;
9315    }
9316
9317    RefPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
9318    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9319        if (!parseFontFeatureTag(settings.get()))
9320            return false;
9321
9322        // If the list isn't parsed fully, the current value should be comma.
9323        value = m_valueList->current();
9324        if (value && !isComma(value))
9325            return false;
9326    }
9327    if (settings->length()) {
9328        addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important);
9329        return true;
9330    }
9331    return false;
9332}
9333
9334bool CSSParser::parseFontVariantLigatures(bool important)
9335{
9336    RefPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
9337    bool sawCommonLigaturesValue = false;
9338    bool sawDiscretionaryLigaturesValue = false;
9339    bool sawHistoricalLigaturesValue = false;
9340
9341    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9342        if (value->unit != CSSPrimitiveValue::CSS_IDENT)
9343            return false;
9344
9345        switch (value->id) {
9346        case CSSValueNoCommonLigatures:
9347        case CSSValueCommonLigatures:
9348            if (sawCommonLigaturesValue)
9349                return false;
9350            sawCommonLigaturesValue = true;
9351            ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9352            break;
9353        case CSSValueNoDiscretionaryLigatures:
9354        case CSSValueDiscretionaryLigatures:
9355            if (sawDiscretionaryLigaturesValue)
9356                return false;
9357            sawDiscretionaryLigaturesValue = true;
9358            ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9359            break;
9360        case CSSValueNoHistoricalLigatures:
9361        case CSSValueHistoricalLigatures:
9362            if (sawHistoricalLigaturesValue)
9363                return false;
9364            sawHistoricalLigaturesValue = true;
9365            ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9366            break;
9367        default:
9368            return false;
9369        }
9370    }
9371
9372    if (!ligatureValues->length())
9373        return false;
9374
9375    addProperty(CSSPropertyWebkitFontVariantLigatures, ligatureValues.release(), important);
9376    return true;
9377}
9378
9379bool CSSParser::parseCalculation(CSSParserValue* value, ValueRange range)
9380{
9381    ASSERT(isCalculation(value));
9382
9383    CSSParserValueList* args = value->function->args.get();
9384    if (!args || !args->size())
9385        return false;
9386
9387    ASSERT(!m_parsedCalculation);
9388    m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
9389
9390    if (!m_parsedCalculation)
9391        return false;
9392
9393    return true;
9394}
9395
9396#define END_TOKEN 0
9397
9398void CSSParser::ensureLineEndings()
9399{
9400    if (!m_lineEndings)
9401        m_lineEndings = lineEndings(*m_source);
9402}
9403
9404CSSParserSelector* CSSParser::createFloatingSelectorWithTagName(const QualifiedName& tagQName)
9405{
9406    CSSParserSelector* selector = new CSSParserSelector(tagQName);
9407    m_floatingSelectors.append(selector);
9408    return selector;
9409}
9410
9411CSSParserSelector* CSSParser::createFloatingSelector()
9412{
9413    CSSParserSelector* selector = new CSSParserSelector;
9414    m_floatingSelectors.append(selector);
9415    return selector;
9416}
9417
9418PassOwnPtr<CSSParserSelector> CSSParser::sinkFloatingSelector(CSSParserSelector* selector)
9419{
9420    if (selector) {
9421        size_t index = m_floatingSelectors.reverseFind(selector);
9422        ASSERT(index != kNotFound);
9423        m_floatingSelectors.remove(index);
9424    }
9425    return adoptPtr(selector);
9426}
9427
9428Vector<OwnPtr<CSSParserSelector> >* CSSParser::createFloatingSelectorVector()
9429{
9430    Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >;
9431    m_floatingSelectorVectors.append(selectorVector);
9432    return selectorVector;
9433}
9434
9435PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > CSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector)
9436{
9437    if (selectorVector) {
9438        size_t index = m_floatingSelectorVectors.reverseFind(selectorVector);
9439        ASSERT(index != kNotFound);
9440        m_floatingSelectorVectors.remove(index);
9441    }
9442    return adoptPtr(selectorVector);
9443}
9444
9445CSSParserValueList* CSSParser::createFloatingValueList()
9446{
9447    CSSParserValueList* list = new CSSParserValueList;
9448    m_floatingValueLists.append(list);
9449    return list;
9450}
9451
9452PassOwnPtr<CSSParserValueList> CSSParser::sinkFloatingValueList(CSSParserValueList* list)
9453{
9454    if (list) {
9455        size_t index = m_floatingValueLists.reverseFind(list);
9456        ASSERT(index != kNotFound);
9457        m_floatingValueLists.remove(index);
9458    }
9459    return adoptPtr(list);
9460}
9461
9462CSSParserFunction* CSSParser::createFloatingFunction()
9463{
9464    CSSParserFunction* function = new CSSParserFunction;
9465    m_floatingFunctions.append(function);
9466    return function;
9467}
9468
9469CSSParserFunction* CSSParser::createFloatingFunction(const CSSParserString& name, PassOwnPtr<CSSParserValueList> args)
9470{
9471    CSSParserFunction* function = createFloatingFunction();
9472    function->name = name;
9473    function->args = args;
9474    return function;
9475}
9476
9477PassOwnPtr<CSSParserFunction> CSSParser::sinkFloatingFunction(CSSParserFunction* function)
9478{
9479    if (function) {
9480        size_t index = m_floatingFunctions.reverseFind(function);
9481        ASSERT(index != kNotFound);
9482        m_floatingFunctions.remove(index);
9483    }
9484    return adoptPtr(function);
9485}
9486
9487CSSParserValue& CSSParser::sinkFloatingValue(CSSParserValue& value)
9488{
9489    if (value.unit == CSSParserValue::Function) {
9490        size_t index = m_floatingFunctions.reverseFind(value.function);
9491        ASSERT(index != kNotFound);
9492        m_floatingFunctions.remove(index);
9493    }
9494    return value;
9495}
9496
9497MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
9498{
9499    m_floatingMediaQueryExp = MediaQueryExp::create(mediaFeature, values);
9500    return m_floatingMediaQueryExp.get();
9501}
9502
9503PassOwnPtr<MediaQueryExp> CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression)
9504{
9505    ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp);
9506    return m_floatingMediaQueryExp.release();
9507}
9508
9509Vector<OwnPtr<MediaQueryExp> >* CSSParser::createFloatingMediaQueryExpList()
9510{
9511    m_floatingMediaQueryExpList = adoptPtr(new Vector<OwnPtr<MediaQueryExp> >);
9512    return m_floatingMediaQueryExpList.get();
9513}
9514
9515PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > CSSParser::sinkFloatingMediaQueryExpList(Vector<OwnPtr<MediaQueryExp> >* list)
9516{
9517    ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList);
9518    return m_floatingMediaQueryExpList.release();
9519}
9520
9521MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const AtomicString& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
9522{
9523    m_floatingMediaQuery = adoptPtr(new MediaQuery(restrictor, mediaType, expressions));
9524    return m_floatingMediaQuery.get();
9525}
9526
9527MediaQuery* CSSParser::createFloatingMediaQuery(PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
9528{
9529    return createFloatingMediaQuery(MediaQuery::None, AtomicString("all", AtomicString::ConstructFromLiteral), expressions);
9530}
9531
9532MediaQuery* CSSParser::createFloatingNotAllQuery()
9533{
9534    return createFloatingMediaQuery(MediaQuery::Not, AtomicString("all", AtomicString::ConstructFromLiteral), sinkFloatingMediaQueryExpList(createFloatingMediaQueryExpList()));
9535}
9536
9537PassOwnPtr<MediaQuery> CSSParser::sinkFloatingMediaQuery(MediaQuery* query)
9538{
9539    ASSERT_UNUSED(query, query == m_floatingMediaQuery);
9540    return m_floatingMediaQuery.release();
9541}
9542
9543Vector<RefPtr<StyleKeyframe> >* CSSParser::createFloatingKeyframeVector()
9544{
9545    m_floatingKeyframeVector = adoptPtr(new Vector<RefPtr<StyleKeyframe> >());
9546    return m_floatingKeyframeVector.get();
9547}
9548
9549PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > CSSParser::sinkFloatingKeyframeVector(Vector<RefPtr<StyleKeyframe> >* keyframeVector)
9550{
9551    ASSERT_UNUSED(keyframeVector, m_floatingKeyframeVector == keyframeVector);
9552    return m_floatingKeyframeVector.release();
9553}
9554
9555MediaQuerySet* CSSParser::createMediaQuerySet()
9556{
9557    RefPtr<MediaQuerySet> queries = MediaQuerySet::create();
9558    MediaQuerySet* result = queries.get();
9559    m_parsedMediaQuerySets.append(queries.release());
9560    return result;
9561}
9562
9563StyleRuleBase* CSSParser::createImportRule(const CSSParserString& url, MediaQuerySet* media)
9564{
9565    if (!media || !m_allowImportRules)
9566        return 0;
9567    RefPtr<StyleRuleImport> rule = StyleRuleImport::create(url, media);
9568    StyleRuleImport* result = rule.get();
9569    m_parsedRules.append(rule.release());
9570    return result;
9571}
9572
9573StyleRuleBase* CSSParser::createMediaRule(MediaQuerySet* media, RuleList* rules)
9574{
9575    m_allowImportRules = m_allowNamespaceDeclarations = false;
9576    RefPtr<StyleRuleMedia> rule;
9577    if (rules) {
9578        rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), *rules);
9579    } else {
9580        RuleList emptyRules;
9581        rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), emptyRules);
9582    }
9583    StyleRuleMedia* result = rule.get();
9584    m_parsedRules.append(rule.release());
9585    return result;
9586}
9587
9588StyleRuleBase* CSSParser::createSupportsRule(bool conditionIsSupported, RuleList* rules)
9589{
9590    m_allowImportRules = m_allowNamespaceDeclarations = false;
9591
9592    RefPtr<CSSRuleSourceData> data = popSupportsRuleData();
9593    RefPtr<StyleRuleSupports> rule;
9594    String conditionText;
9595    unsigned conditionOffset = data->ruleHeaderRange.start + 9;
9596    unsigned conditionLength = data->ruleHeaderRange.length() - 9;
9597
9598    if (m_tokenizer.is8BitSource())
9599        conditionText = String(m_tokenizer.m_dataStart8.get() + conditionOffset, conditionLength).stripWhiteSpace();
9600    else
9601        conditionText = String(m_tokenizer.m_dataStart16.get() + conditionOffset, conditionLength).stripWhiteSpace();
9602
9603    if (rules) {
9604        rule = StyleRuleSupports::create(conditionText, conditionIsSupported, *rules);
9605    } else {
9606        RuleList emptyRules;
9607        rule = StyleRuleSupports::create(conditionText, conditionIsSupported, emptyRules);
9608    }
9609
9610    StyleRuleSupports* result = rule.get();
9611    m_parsedRules.append(rule.release());
9612
9613    return result;
9614}
9615
9616void CSSParser::markSupportsRuleHeaderStart()
9617{
9618    if (!m_supportsRuleDataStack)
9619        m_supportsRuleDataStack = adoptPtr(new RuleSourceDataList());
9620
9621    RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(CSSRuleSourceData::SUPPORTS_RULE);
9622    data->ruleHeaderRange.start = m_tokenizer.tokenStartOffset();
9623    m_supportsRuleDataStack->append(data);
9624}
9625
9626void CSSParser::markSupportsRuleHeaderEnd()
9627{
9628    ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
9629
9630    if (m_tokenizer.is8BitSource())
9631        m_supportsRuleDataStack->last()->ruleHeaderRange.end = m_tokenizer.tokenStart<LChar>() - m_tokenizer.m_dataStart8.get();
9632    else
9633        m_supportsRuleDataStack->last()->ruleHeaderRange.end = m_tokenizer.tokenStart<UChar>() - m_tokenizer.m_dataStart16.get();
9634}
9635
9636PassRefPtr<CSSRuleSourceData> CSSParser::popSupportsRuleData()
9637{
9638    ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
9639    RefPtr<CSSRuleSourceData> data = m_supportsRuleDataStack->last();
9640    m_supportsRuleDataStack->removeLast();
9641    return data.release();
9642}
9643
9644CSSParser::RuleList* CSSParser::createRuleList()
9645{
9646    OwnPtr<RuleList> list = adoptPtr(new RuleList);
9647    RuleList* listPtr = list.get();
9648
9649    m_parsedRuleLists.append(list.release());
9650    return listPtr;
9651}
9652
9653CSSParser::RuleList* CSSParser::appendRule(RuleList* ruleList, StyleRuleBase* rule)
9654{
9655    if (rule) {
9656        if (!ruleList)
9657            ruleList = createRuleList();
9658        ruleList->append(rule);
9659    }
9660    return ruleList;
9661}
9662
9663template <typename CharacterType>
9664ALWAYS_INLINE static void makeLower(const CharacterType* input, CharacterType* output, unsigned length)
9665{
9666    // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
9667    // that can potentially change the length of the string rather than the character
9668    // by character kind. If we don't need Unicode lowercasing, it would be good to
9669    // simplify this function.
9670
9671    if (charactersAreAllASCII(input, length)) {
9672        // Fast case for all-ASCII.
9673        for (unsigned i = 0; i < length; i++)
9674            output[i] = toASCIILower(input[i]);
9675    } else {
9676        for (unsigned i = 0; i < length; i++)
9677            output[i] = Unicode::toLower(input[i]);
9678    }
9679}
9680
9681void CSSParser::tokenToLowerCase(const CSSParserString& token)
9682{
9683    size_t length = token.length();
9684    if (m_tokenizer.is8BitSource()) {
9685        size_t offset = token.characters8() - m_tokenizer.m_dataStart8.get();
9686        makeLower(token.characters8(), m_tokenizer.m_dataStart8.get() + offset, length);
9687    } else {
9688        size_t offset = token.characters16() - m_tokenizer.m_dataStart16.get();
9689        makeLower(token.characters16(), m_tokenizer.m_dataStart16.get() + offset, length);
9690    }
9691}
9692
9693void CSSParser::endInvalidRuleHeader()
9694{
9695    if (m_ruleHeaderType == CSSRuleSourceData::UNKNOWN_RULE)
9696        return;
9697
9698    CSSParserLocation location;
9699    location.lineNumber = m_tokenizer.m_lineNumber;
9700    location.offset = m_ruleHeaderStartOffset;
9701    if (m_tokenizer.is8BitSource())
9702        location.token.init(m_tokenizer.m_dataStart8.get() + m_ruleHeaderStartOffset, 0);
9703    else
9704        location.token.init(m_tokenizer.m_dataStart16.get() + m_ruleHeaderStartOffset, 0);
9705
9706    reportError(location, m_ruleHeaderType == CSSRuleSourceData::STYLE_RULE ? InvalidSelectorError : InvalidRuleError);
9707
9708    endRuleHeader();
9709}
9710
9711void CSSParser::reportError(const CSSParserLocation&, ErrorType)
9712{
9713    // FIXME: error reporting temporatily disabled.
9714}
9715
9716bool CSSParser::isLoggingErrors()
9717{
9718    return m_logErrors && !m_ignoreErrors;
9719}
9720
9721void CSSParser::logError(const String& message, const CSSParserLocation& location)
9722{
9723    unsigned lineNumberInStyleSheet;
9724    unsigned columnNumber = 0;
9725    PageConsole& console = m_styleSheet->singleOwnerDocument()->page()->console();
9726    if (InspectorInstrumentation::hasFrontends()) {
9727        ensureLineEndings();
9728        TextPosition tokenPosition = TextPosition::fromOffsetAndLineEndings(location.offset, *m_lineEndings);
9729        lineNumberInStyleSheet = tokenPosition.m_line.zeroBasedInt();
9730        columnNumber = (lineNumberInStyleSheet ? 0 : m_startPosition.m_column.zeroBasedInt()) + tokenPosition.m_column.zeroBasedInt();
9731    } else {
9732        lineNumberInStyleSheet = location.lineNumber;
9733    }
9734    console.addMessage(CSSMessageSource, WarningMessageLevel, message, m_styleSheet->baseURL().string(), lineNumberInStyleSheet + m_startPosition.m_line.zeroBasedInt() + 1, columnNumber + 1);
9735}
9736
9737StyleRuleKeyframes* CSSParser::createKeyframesRule(const String& name, PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > popKeyframes, bool isPrefixed)
9738{
9739    OwnPtr<Vector<RefPtr<StyleKeyframe> > > keyframes = popKeyframes;
9740    m_allowImportRules = m_allowNamespaceDeclarations = false;
9741    RefPtr<StyleRuleKeyframes> rule = StyleRuleKeyframes::create();
9742    for (size_t i = 0; i < keyframes->size(); ++i)
9743        rule->parserAppendKeyframe(keyframes->at(i));
9744    rule->setName(name);
9745    rule->setVendorPrefixed(isPrefixed);
9746    StyleRuleKeyframes* rulePtr = rule.get();
9747    m_parsedRules.append(rule.release());
9748    return rulePtr;
9749}
9750
9751StyleRuleBase* CSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors)
9752{
9753    StyleRule* result = 0;
9754    if (selectors) {
9755        m_allowImportRules = m_allowNamespaceDeclarations = false;
9756        RefPtr<StyleRule> rule = StyleRule::create();
9757        rule->parserAdoptSelectorVector(*selectors);
9758        if (m_hasFontFaceOnlyValues)
9759            deleteFontFaceOnlyValues();
9760        rule->setProperties(createStylePropertySet());
9761        result = rule.get();
9762        m_parsedRules.append(rule.release());
9763    }
9764    clearProperties();
9765    return result;
9766}
9767
9768StyleRuleBase* CSSParser::createFontFaceRule()
9769{
9770    m_allowImportRules = m_allowNamespaceDeclarations = false;
9771    for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
9772        CSSProperty& property = m_parsedProperties[i];
9773        if (property.id() == CSSPropertyFontVariant && property.value()->isPrimitiveValue())
9774            property.wrapValueInCommaSeparatedList();
9775        else if (property.id() == CSSPropertyFontFamily && (!property.value()->isValueList() || toCSSValueList(property.value())->length() != 1)) {
9776            // Unlike font-family property, font-family descriptor in @font-face rule
9777            // has to be a value list with exactly one family name. It cannot have a
9778            // have 'initial' value and cannot 'inherit' from parent.
9779            // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
9780            clearProperties();
9781            return 0;
9782        }
9783    }
9784    RefPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create();
9785    rule->setProperties(createStylePropertySet());
9786    clearProperties();
9787    StyleRuleFontFace* result = rule.get();
9788    m_parsedRules.append(rule.release());
9789    if (m_styleSheet)
9790        m_styleSheet->setHasFontFaceRule(true);
9791    return result;
9792}
9793
9794void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
9795{
9796    if (!m_styleSheet || !m_allowNamespaceDeclarations)
9797        return;
9798    m_allowImportRules = false;
9799    m_styleSheet->parserAddNamespace(prefix, uri);
9800    if (prefix.isEmpty() && !uri.isNull())
9801        m_defaultNamespace = uri;
9802}
9803
9804QualifiedName CSSParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName)
9805{
9806    if (!m_styleSheet)
9807        return QualifiedName(prefix, localName, m_defaultNamespace);
9808    return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix));
9809}
9810
9811CSSParserSelector* CSSParser::rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector* specifiers)
9812{
9813    if (m_defaultNamespace != starAtom || specifiers->needsCrossingTreeScopeBoundary())
9814        return rewriteSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true);
9815    if (CSSParserSelector* distributedPseudoElementSelector = specifiers->findDistributedPseudoElementSelector()) {
9816        specifiers->prependTagSelector(QualifiedName(nullAtom, starAtom, m_defaultNamespace), /*tagIsForNamespaceRule*/true);
9817        return rewriteSpecifiersForShadowDistributed(specifiers, distributedPseudoElementSelector);
9818    }
9819    return specifiers;
9820}
9821
9822CSSParserSelector* CSSParser::rewriteSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
9823{
9824    AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
9825    QualifiedName tag(namespacePrefix, elementName, determinedNamespace);
9826
9827    if (CSSParserSelector* distributedPseudoElementSelector = specifiers->findDistributedPseudoElementSelector()) {
9828        specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
9829        return rewriteSpecifiersForShadowDistributed(specifiers, distributedPseudoElementSelector);
9830    }
9831
9832    if (specifiers->needsCrossingTreeScopeBoundary())
9833        return rewriteSpecifiersWithElementNameForCustomPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
9834
9835    if (specifiers->isContentPseudoElement())
9836        return rewriteSpecifiersWithElementNameForContentPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
9837
9838    if (tag == anyQName())
9839        return specifiers;
9840    if (!(specifiers->pseudoType() == CSSSelector::PseudoCue))
9841        specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
9842    return specifiers;
9843}
9844
9845CSSParserSelector* CSSParser::rewriteSpecifiersWithElementNameForCustomPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
9846{
9847    if (m_useCounter && specifiers->pseudoType() == CSSSelector::PseudoUserAgentCustomElement)
9848        m_useCounter->count(UseCounter::CSSPseudoElementUserAgentCustomPseudo);
9849
9850    CSSParserSelector* lastShadowPseudo = specifiers;
9851    CSSParserSelector* history = specifiers;
9852    while (history->tagHistory()) {
9853        history = history->tagHistory();
9854        if (history->needsCrossingTreeScopeBoundary() || history->hasShadowPseudo())
9855            lastShadowPseudo = history;
9856    }
9857
9858    if (lastShadowPseudo->tagHistory()) {
9859        if (tag != anyQName())
9860            lastShadowPseudo->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
9861        return specifiers;
9862    }
9863
9864    // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
9865    // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
9866    OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
9867    lastShadowPseudo->setTagHistory(elementNameSelector.release());
9868    lastShadowPseudo->setRelation(CSSSelector::ShadowPseudo);
9869    return specifiers;
9870}
9871
9872CSSParserSelector* CSSParser::rewriteSpecifiersWithElementNameForContentPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
9873{
9874    CSSParserSelector* last = specifiers;
9875    CSSParserSelector* history = specifiers;
9876    while (history->tagHistory()) {
9877        history = history->tagHistory();
9878        if (history->isContentPseudoElement() || history->relationIsAffectedByPseudoContent())
9879            last = history;
9880    }
9881
9882    if (last->tagHistory()) {
9883        if (tag != anyQName())
9884            last->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
9885        return specifiers;
9886    }
9887
9888    // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
9889    // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
9890    OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
9891    last->setTagHistory(elementNameSelector.release());
9892    last->setRelation(CSSSelector::SubSelector);
9893    return specifiers;
9894}
9895
9896CSSParserSelector* CSSParser::rewriteSpecifiersForShadowDistributed(CSSParserSelector* specifiers, CSSParserSelector* distributedPseudoElementSelector)
9897{
9898    if (m_useCounter)
9899        m_useCounter->count(UseCounter::CSSPseudoElementPrefixedDistributed);
9900    CSSParserSelector* argumentSelector = distributedPseudoElementSelector->functionArgumentSelector();
9901    ASSERT(argumentSelector);
9902    ASSERT(!specifiers->isDistributedPseudoElement());
9903    for (CSSParserSelector* end = specifiers; end->tagHistory(); end = end->tagHistory()) {
9904        if (end->tagHistory()->isDistributedPseudoElement()) {
9905            end->clearTagHistory();
9906            break;
9907        }
9908    }
9909    CSSParserSelector* end = argumentSelector;
9910    while (end->tagHistory())
9911        end = end->tagHistory();
9912
9913    switch (end->relation()) {
9914    case CSSSelector::Child:
9915    case CSSSelector::Descendant:
9916        end->setTagHistory(sinkFloatingSelector(specifiers));
9917        end->setRelationIsAffectedByPseudoContent();
9918        return argumentSelector;
9919    default:
9920        return 0;
9921    }
9922}
9923
9924CSSParserSelector* CSSParser::rewriteSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier)
9925{
9926    if (newSpecifier->needsCrossingTreeScopeBoundary()) {
9927        // Unknown pseudo element always goes at the top of selector chain.
9928        newSpecifier->appendTagHistory(CSSSelector::ShadowPseudo, sinkFloatingSelector(specifiers));
9929        return newSpecifier;
9930    }
9931    if (newSpecifier->isContentPseudoElement()) {
9932        newSpecifier->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(specifiers));
9933        return newSpecifier;
9934    }
9935    if (specifiers->needsCrossingTreeScopeBoundary()) {
9936        // Specifiers for unknown pseudo element go right behind it in the chain.
9937        specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::ShadowPseudo);
9938        return specifiers;
9939    }
9940    if (specifiers->isContentPseudoElement()) {
9941        specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::SubSelector);
9942        return specifiers;
9943    }
9944    specifiers->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier));
9945    return specifiers;
9946}
9947
9948StyleRuleBase* CSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector)
9949{
9950    // FIXME: Margin at-rules are ignored.
9951    m_allowImportRules = m_allowNamespaceDeclarations = false;
9952    StyleRulePage* pageRule = 0;
9953    if (pageSelector) {
9954        RefPtr<StyleRulePage> rule = StyleRulePage::create();
9955        Vector<OwnPtr<CSSParserSelector> > selectorVector;
9956        selectorVector.append(pageSelector);
9957        rule->parserAdoptSelectorVector(selectorVector);
9958        rule->setProperties(createStylePropertySet());
9959        pageRule = rule.get();
9960        m_parsedRules.append(rule.release());
9961    }
9962    clearProperties();
9963    return pageRule;
9964}
9965
9966void CSSParser::setReusableRegionSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectors)
9967{
9968    if (selectors)
9969        m_reusableRegionSelectorVector.swap(*selectors);
9970}
9971
9972StyleRuleBase* CSSParser::createRegionRule(Vector<OwnPtr<CSSParserSelector> >* regionSelector, RuleList* rules)
9973{
9974    if (m_useCounter)
9975        m_useCounter->count(UseCounter::CSSWebkitRegionAtRule);
9976
9977    if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !regionSelector || !rules)
9978        return 0;
9979
9980    m_allowImportRules = m_allowNamespaceDeclarations = false;
9981
9982    RefPtr<StyleRuleRegion> regionRule = StyleRuleRegion::create(regionSelector, *rules);
9983
9984    StyleRuleRegion* result = regionRule.get();
9985    m_parsedRules.append(regionRule.release());
9986    if (m_sourceDataHandler)
9987        m_sourceDataHandler->startEndUnknownRule();
9988
9989    return result;
9990}
9991
9992StyleRuleBase* CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
9993{
9994    // FIXME: Implement margin at-rule here, using:
9995    //        - marginBox: margin box
9996    //        - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_parsedProperties.size()] are for this at-rule.
9997    // Don't forget to also update the action for page symbol in CSSGrammar.y such that margin at-rule data is cleared if page_selector is invalid.
9998
9999    endDeclarationsForMarginBox();
10000    return 0; // until this method is implemented.
10001}
10002
10003void CSSParser::startDeclarationsForMarginBox()
10004{
10005    m_numParsedPropertiesBeforeMarginBox = m_parsedProperties.size();
10006}
10007
10008void CSSParser::endDeclarationsForMarginBox()
10009{
10010    rollbackLastProperties(m_parsedProperties.size() - m_numParsedPropertiesBeforeMarginBox);
10011    m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
10012}
10013
10014void CSSParser::deleteFontFaceOnlyValues()
10015{
10016    ASSERT(m_hasFontFaceOnlyValues);
10017    for (unsigned i = 0; i < m_parsedProperties.size();) {
10018        CSSProperty& property = m_parsedProperties[i];
10019        if (property.id() == CSSPropertyFontVariant && property.value()->isValueList()) {
10020            m_parsedProperties.remove(i);
10021            continue;
10022        }
10023        ++i;
10024    }
10025}
10026
10027StyleKeyframe* CSSParser::createKeyframe(CSSParserValueList* keys)
10028{
10029    OwnPtr<Vector<double> > keyVector = StyleKeyframe::createKeyList(keys);
10030    if (keyVector->isEmpty())
10031        return 0;
10032
10033    RefPtr<StyleKeyframe> keyframe = StyleKeyframe::create();
10034    keyframe->setKeys(keyVector.release());
10035    keyframe->setProperties(createStylePropertySet());
10036
10037    clearProperties();
10038
10039    StyleKeyframe* keyframePtr = keyframe.get();
10040    m_parsedKeyframes.append(keyframe.release());
10041    return keyframePtr;
10042}
10043
10044void CSSParser::invalidBlockHit()
10045{
10046    if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
10047        m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
10048}
10049
10050void CSSParser::startRule()
10051{
10052    if (!m_sourceDataHandler)
10053        return;
10054
10055    ASSERT(m_ruleHasHeader);
10056    m_ruleHasHeader = false;
10057}
10058
10059void CSSParser::endRule(bool valid)
10060{
10061    if (!m_sourceDataHandler)
10062        return;
10063
10064    if (m_ruleHasHeader)
10065        m_sourceDataHandler->endRuleBody(m_tokenizer.safeUserStringTokenOffset(), !valid);
10066    m_ruleHasHeader = true;
10067}
10068
10069void CSSParser::startRuleHeader(CSSRuleSourceData::Type ruleType)
10070{
10071    resumeErrorLogging();
10072    m_ruleHeaderType = ruleType;
10073    m_ruleHeaderStartOffset = m_tokenizer.safeUserStringTokenOffset();
10074    m_ruleHeaderStartLineNumber = m_tokenizer.m_tokenStartLineNumber;
10075    if (m_sourceDataHandler) {
10076        ASSERT(!m_ruleHasHeader);
10077        m_sourceDataHandler->startRuleHeader(ruleType, m_ruleHeaderStartOffset);
10078        m_ruleHasHeader = true;
10079    }
10080}
10081
10082void CSSParser::endRuleHeader()
10083{
10084    ASSERT(m_ruleHeaderType != CSSRuleSourceData::UNKNOWN_RULE);
10085    m_ruleHeaderType = CSSRuleSourceData::UNKNOWN_RULE;
10086    if (m_sourceDataHandler) {
10087        ASSERT(m_ruleHasHeader);
10088        m_sourceDataHandler->endRuleHeader(m_tokenizer.safeUserStringTokenOffset());
10089    }
10090}
10091
10092void CSSParser::startSelector()
10093{
10094    if (m_sourceDataHandler)
10095        m_sourceDataHandler->startSelector(m_tokenizer.safeUserStringTokenOffset());
10096}
10097
10098void CSSParser::endSelector()
10099{
10100    if (m_sourceDataHandler)
10101        m_sourceDataHandler->endSelector(m_tokenizer.safeUserStringTokenOffset());
10102}
10103
10104void CSSParser::startRuleBody()
10105{
10106    if (m_sourceDataHandler)
10107        m_sourceDataHandler->startRuleBody(m_tokenizer.safeUserStringTokenOffset());
10108}
10109
10110void CSSParser::startProperty()
10111{
10112    resumeErrorLogging();
10113    if (m_sourceDataHandler)
10114        m_sourceDataHandler->startProperty(m_tokenizer.safeUserStringTokenOffset());
10115}
10116
10117void CSSParser::endProperty(bool isImportantFound, bool isPropertyParsed, ErrorType errorType)
10118{
10119    m_id = CSSPropertyInvalid;
10120    if (m_sourceDataHandler)
10121        m_sourceDataHandler->endProperty(isImportantFound, isPropertyParsed, m_tokenizer.safeUserStringTokenOffset(), errorType);
10122}
10123
10124void CSSParser::startEndUnknownRule()
10125{
10126    if (m_sourceDataHandler)
10127        m_sourceDataHandler->startEndUnknownRule();
10128}
10129
10130StyleRuleBase* CSSParser::createViewportRule()
10131{
10132    // Allow @viewport rules from UA stylesheets even if the feature is disabled.
10133    if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode()))
10134        return 0;
10135
10136    m_allowImportRules = m_allowNamespaceDeclarations = false;
10137
10138    RefPtr<StyleRuleViewport> rule = StyleRuleViewport::create();
10139
10140    rule->setProperties(createStylePropertySet());
10141    clearProperties();
10142
10143    StyleRuleViewport* result = rule.get();
10144    m_parsedRules.append(rule.release());
10145
10146    return result;
10147}
10148
10149bool CSSParser::parseViewportProperty(CSSPropertyID propId, bool important)
10150{
10151    ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
10152
10153    CSSParserValue* value = m_valueList->current();
10154    if (!value)
10155        return false;
10156
10157    CSSValueID id = value->id;
10158    bool validPrimitive = false;
10159
10160    switch (propId) {
10161    case CSSPropertyMinWidth: // auto | extend-to-zoom | <length> | <percentage>
10162    case CSSPropertyMaxWidth:
10163    case CSSPropertyMinHeight:
10164    case CSSPropertyMaxHeight:
10165        if (id == CSSValueAuto || id == CSSValueInternalExtendToZoom)
10166            validPrimitive = true;
10167        else
10168            validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
10169        break;
10170    case CSSPropertyWidth: // shorthand
10171        return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMaxWidth, important);
10172    case CSSPropertyHeight:
10173        return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyMaxHeight, important);
10174    case CSSPropertyMinZoom: // auto | <number> | <percentage>
10175    case CSSPropertyMaxZoom:
10176    case CSSPropertyZoom:
10177        if (id == CSSValueAuto)
10178            validPrimitive = true;
10179        else
10180            validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg));
10181        break;
10182    case CSSPropertyUserZoom: // zoom | fixed
10183        if (id == CSSValueZoom || id == CSSValueFixed)
10184            validPrimitive = true;
10185        break;
10186    case CSSPropertyOrientation: // auto | portrait | landscape
10187        if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandscape)
10188            validPrimitive = true;
10189    default:
10190        break;
10191    }
10192
10193    RefPtr<CSSValue> parsedValue;
10194    if (validPrimitive) {
10195        parsedValue = parseValidPrimitive(id, value);
10196        m_valueList->next();
10197    }
10198
10199    if (parsedValue) {
10200        if (!m_valueList->current() || inShorthand()) {
10201            addProperty(propId, parsedValue.release(), important);
10202            return true;
10203        }
10204    }
10205
10206    return false;
10207}
10208
10209bool CSSParser::parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first, CSSPropertyID second, bool important)
10210{
10211    ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
10212    unsigned numValues = m_valueList->size();
10213
10214    if (numValues > 2)
10215        return false;
10216
10217    ShorthandScope scope(this, propId);
10218
10219    if (!parseViewportProperty(first, important))
10220        return false;
10221
10222    // If just one value is supplied, the second value
10223    // is implicitly initialized with the first value.
10224    if (numValues == 1)
10225        m_valueList->previous();
10226
10227    return parseViewportProperty(second, important);
10228}
10229
10230template <typename CharacterType>
10231static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
10232{
10233    char buffer[maxCSSPropertyNameLength + 1]; // 1 for null character
10234
10235    for (unsigned i = 0; i != length; ++i) {
10236        CharacterType c = propertyName[i];
10237        if (c == 0 || c >= 0x7F)
10238            return CSSPropertyInvalid; // illegal character
10239        buffer[i] = toASCIILower(c);
10240    }
10241    buffer[length] = '\0';
10242
10243    const char* name = buffer;
10244    const Property* hashTableEntry = findProperty(name, length);
10245    return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
10246}
10247
10248CSSPropertyID cssPropertyID(const String& string)
10249{
10250    unsigned length = string.length();
10251
10252    if (!length)
10253        return CSSPropertyInvalid;
10254    if (length > maxCSSPropertyNameLength)
10255        return CSSPropertyInvalid;
10256
10257    return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
10258}
10259
10260CSSPropertyID cssPropertyID(const CSSParserString& string)
10261{
10262    unsigned length = string.length();
10263
10264    if (!length)
10265        return CSSPropertyInvalid;
10266    if (length > maxCSSPropertyNameLength)
10267        return CSSPropertyInvalid;
10268
10269    return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
10270}
10271
10272template <typename CharacterType>
10273static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
10274{
10275    char buffer[maxCSSValueKeywordLength + 1]; // 1 for null character
10276
10277    for (unsigned i = 0; i != length; ++i) {
10278        CharacterType c = valueKeyword[i];
10279        if (c == 0 || c >= 0x7F)
10280            return CSSValueInvalid; // illegal character
10281        buffer[i] = WTF::toASCIILower(c);
10282    }
10283    buffer[length] = '\0';
10284
10285    const Value* hashTableEntry = findValue(buffer, length);
10286    return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSValueInvalid;
10287}
10288
10289CSSValueID cssValueKeywordID(const CSSParserString& string)
10290{
10291    unsigned length = string.length();
10292    if (!length)
10293        return CSSValueInvalid;
10294    if (length > maxCSSValueKeywordLength)
10295        return CSSValueInvalid;
10296
10297    return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
10298}
10299
10300template <typename CharacterType>
10301static inline bool isCSSTokenizerIdentifier(const CharacterType* characters, unsigned length)
10302{
10303    const CharacterType* end = characters + length;
10304
10305    // -?
10306    if (characters != end && characters[0] == '-')
10307        ++characters;
10308
10309    // {nmstart}
10310    if (characters == end || !(characters[0] == '_' || characters[0] >= 128 || isASCIIAlpha(characters[0])))
10311        return false;
10312    ++characters;
10313
10314    // {nmchar}*
10315    for (; characters != end; ++characters) {
10316        if (!(characters[0] == '_' || characters[0] == '-' || characters[0] >= 128 || isASCIIAlphanumeric(characters[0])))
10317            return false;
10318    }
10319
10320    return true;
10321}
10322
10323// "ident" from the CSS tokenizer, minus backslash-escape sequences
10324static bool isCSSTokenizerIdentifier(const String& string)
10325{
10326    unsigned length = string.length();
10327
10328    if (!length)
10329        return false;
10330
10331    if (string.is8Bit())
10332        return isCSSTokenizerIdentifier(string.characters8(), length);
10333    return isCSSTokenizerIdentifier(string.characters16(), length);
10334}
10335
10336template <typename CharacterType>
10337static inline bool isCSSTokenizerURL(const CharacterType* characters, unsigned length)
10338{
10339    const CharacterType* end = characters + length;
10340
10341    for (; characters != end; ++characters) {
10342        CharacterType c = characters[0];
10343        switch (c) {
10344            case '!':
10345            case '#':
10346            case '$':
10347            case '%':
10348            case '&':
10349                break;
10350            default:
10351                if (c < '*')
10352                    return false;
10353                if (c <= '~')
10354                    break;
10355                if (c < 128)
10356                    return false;
10357        }
10358    }
10359
10360    return true;
10361}
10362
10363// "url" from the CSS tokenizer, minus backslash-escape sequences
10364static bool isCSSTokenizerURL(const String& string)
10365{
10366    unsigned length = string.length();
10367
10368    if (!length)
10369        return true;
10370
10371    if (string.is8Bit())
10372        return isCSSTokenizerURL(string.characters8(), length);
10373    return isCSSTokenizerURL(string.characters16(), length);
10374}
10375
10376
10377template <typename CharacterType>
10378static inline String quoteCSSStringInternal(const CharacterType* characters, unsigned length)
10379{
10380    // For efficiency, we first pre-calculate the length of the quoted string, then we build the actual one.
10381    // Please see below for the actual logic.
10382    unsigned quotedStringSize = 2; // Two quotes surrounding the entire string.
10383    bool afterEscape = false;
10384    for (unsigned i = 0; i < length; ++i) {
10385        CharacterType ch = characters[i];
10386        if (ch == '\\' || ch == '\'') {
10387            quotedStringSize += 2;
10388            afterEscape = false;
10389        } else if (ch < 0x20 || ch == 0x7F) {
10390            quotedStringSize += 2 + (ch >= 0x10);
10391            afterEscape = true;
10392        } else {
10393            quotedStringSize += 1 + (afterEscape && (isASCIIHexDigit(ch) || ch == ' '));
10394            afterEscape = false;
10395        }
10396    }
10397
10398    StringBuffer<CharacterType> buffer(quotedStringSize);
10399    unsigned index = 0;
10400    buffer[index++] = '\'';
10401    afterEscape = false;
10402    for (unsigned i = 0; i < length; ++i) {
10403        CharacterType ch = characters[i];
10404        if (ch == '\\' || ch == '\'') {
10405            buffer[index++] = '\\';
10406            buffer[index++] = ch;
10407            afterEscape = false;
10408        } else if (ch < 0x20 || ch == 0x7F) { // Control characters.
10409            buffer[index++] = '\\';
10410            placeByteAsHexCompressIfPossible(ch, buffer, index, Lowercase);
10411            afterEscape = true;
10412        } else {
10413            // Space character may be required to separate backslash-escape sequence and normal characters.
10414            if (afterEscape && (isASCIIHexDigit(ch) || ch == ' '))
10415                buffer[index++] = ' ';
10416            buffer[index++] = ch;
10417            afterEscape = false;
10418        }
10419    }
10420    buffer[index++] = '\'';
10421
10422    ASSERT(quotedStringSize == index);
10423    return String::adopt(buffer);
10424}
10425
10426// We use single quotes for now because markup.cpp uses double quotes.
10427String quoteCSSString(const String& string)
10428{
10429    // This function expands each character to at most 3 characters ('\u0010' -> '\' '1' '0') as well as adds
10430    // 2 quote characters (before and after). Make sure the resulting size (3 * length + 2) will not overflow unsigned.
10431
10432    unsigned length = string.length();
10433
10434    if (!length)
10435        return String("\'\'");
10436
10437    if (length > std::numeric_limits<unsigned>::max() / 3 - 2)
10438        return emptyString();
10439
10440    if (string.is8Bit())
10441        return quoteCSSStringInternal(string.characters8(), length);
10442    return quoteCSSStringInternal(string.characters16(), length);
10443}
10444
10445String quoteCSSStringIfNeeded(const String& string)
10446{
10447    return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string);
10448}
10449
10450String quoteCSSURLIfNeeded(const String& string)
10451{
10452    return isCSSTokenizerURL(string) ? string : quoteCSSString(string);
10453}
10454
10455bool isValidNthToken(const CSSParserString& token)
10456{
10457    // The tokenizer checks for the construct of an+b.
10458    // However, since the {ident} rule precedes the {nth} rule, some of those
10459    // tokens are identified as string literal. Furthermore we need to accept
10460    // "odd" and "even" which does not match to an+b.
10461    return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
10462        || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");
10463}
10464
10465}
10466