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, 2013 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, 2013 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 "CSSParser.h"
29
30#include "CSSAspectRatioValue.h"
31#include "CSSBasicShapes.h"
32#include "CSSBorderImage.h"
33#include "CSSCanvasValue.h"
34#include "CSSCrossfadeValue.h"
35#include "CSSCursorImageValue.h"
36#include "CSSFilterImageValue.h"
37#include "CSSFontFaceRule.h"
38#include "CSSFontFaceSrcValue.h"
39#include "CSSFontFeatureValue.h"
40#include "CSSFontValue.h"
41#include "CSSFunctionValue.h"
42#include "CSSGradientValue.h"
43#include "CSSImageValue.h"
44#include "CSSInheritedValue.h"
45#include "CSSInitialValue.h"
46#include "CSSLineBoxContainValue.h"
47#include "CSSMediaRule.h"
48#include "CSSPageRule.h"
49#include "CSSPrimitiveValue.h"
50#include "CSSPropertySourceData.h"
51#include "CSSReflectValue.h"
52#include "CSSSelector.h"
53#include "CSSShadowValue.h"
54#include "CSSStyleSheet.h"
55#include "CSSTimingFunctionValue.h"
56#include "CSSUnicodeRangeValue.h"
57#include "CSSValueKeywords.h"
58#include "CSSValueList.h"
59#include "CSSValuePool.h"
60#include "Counter.h"
61#include "Document.h"
62#include "FloatConversion.h"
63#include "HTMLParserIdioms.h"
64#include "HashTools.h"
65#include "MediaList.h"
66#include "MediaQueryExp.h"
67#include "Page.h"
68#include "PageConsole.h"
69#include "Pair.h"
70#include "Rect.h"
71#include "RenderTheme.h"
72#include "RuntimeEnabledFeatures.h"
73#include "SVGParserUtilities.h"
74#include "Settings.h"
75#include "StyleProperties.h"
76#include "StylePropertyShorthand.h"
77#include "StyleRule.h"
78#include "StyleRuleImport.h"
79#include "StyleSheetContents.h"
80#include "TextEncoding.h"
81#include "WebKitCSSKeyframeRule.h"
82#include "WebKitCSSKeyframesRule.h"
83#include "WebKitCSSRegionRule.h"
84#include "WebKitCSSTransformValue.h"
85#include <bitset>
86#include <limits.h>
87#include <wtf/HexNumber.h>
88#include <wtf/NeverDestroyed.h>
89#include <wtf/StdLibExtras.h>
90#include <wtf/dtoa.h>
91#include <wtf/text/StringBuffer.h>
92#include <wtf/text/StringBuilder.h>
93#include <wtf/text/StringImpl.h>
94
95#if ENABLE(CSS_GRID_LAYOUT)
96#include "CSSGridLineNamesValue.h"
97#endif
98
99#if ENABLE(CSS_IMAGE_SET)
100#include "CSSImageSetValue.h"
101#endif
102
103#if ENABLE(CSS_FILTERS)
104#include "WebKitCSSFilterValue.h"
105#endif
106
107#if ENABLE(DASHBOARD_SUPPORT)
108#include "DashboardRegion.h"
109#endif
110
111#define YYDEBUG 0
112
113#if YYDEBUG > 0
114extern int cssyydebug;
115#endif
116
117extern int cssyyparse(WebCore::CSSParser*);
118
119using namespace WTF;
120
121namespace {
122
123enum PropertyType {
124    PropertyExplicit,
125    PropertyImplicit
126};
127
128class ImplicitScope {
129    WTF_MAKE_NONCOPYABLE(ImplicitScope);
130public:
131    ImplicitScope(WebCore::CSSParser* parser, PropertyType propertyType)
132        : m_parser(parser)
133    {
134        m_parser->m_implicitShorthand = propertyType == PropertyImplicit;
135    }
136
137    ~ImplicitScope()
138    {
139        m_parser->m_implicitShorthand = false;
140    }
141
142private:
143    WebCore::CSSParser* m_parser;
144};
145
146} // namespace
147
148namespace WebCore {
149
150static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
151static const double MAX_SCALE = 1000000;
152#if ENABLE(CSS_GRID_LAYOUT)
153static const unsigned MAX_GRID_TRACK_REPETITIONS = 10000;
154#endif
155
156template <unsigned N>
157static bool equal(const CSSParserString& a, const char (&b)[N])
158{
159    unsigned length = N - 1; // Ignore the trailing null character
160    if (a.length() != length)
161        return false;
162
163    return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar*>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length);
164}
165
166template <unsigned N>
167static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
168{
169    unsigned length = N - 1; // Ignore the trailing null character
170    if (a.length() != length)
171        return false;
172
173    return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length);
174}
175
176template <unsigned N>
177static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N])
178{
179    ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrimitiveValue::CSS_STRING);
180    return equalIgnoringCase(value->string, b);
181}
182
183static bool hasPrefix(const char* string, unsigned length, const char* prefix)
184{
185    for (unsigned i = 0; i < length; ++i) {
186        if (!prefix[i])
187            return true;
188        if (string[i] != prefix[i])
189            return false;
190    }
191    return false;
192}
193
194static PassRefPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtr<CSSPrimitiveValue> first, PassRefPtr<CSSPrimitiveValue> second)
195{
196    return cssValuePool().createValue(Pair::create(first, second));
197}
198
199class AnimationParseContext {
200public:
201    AnimationParseContext()
202        : m_animationPropertyKeywordAllowed(true)
203        , m_firstAnimationCommitted(false)
204        , m_hasSeenAnimationPropertyKeyword(false)
205    {
206    }
207
208    void commitFirstAnimation()
209    {
210        m_firstAnimationCommitted = true;
211    }
212
213    bool hasCommittedFirstAnimation() const
214    {
215        return m_firstAnimationCommitted;
216    }
217
218    void commitAnimationPropertyKeyword()
219    {
220        m_animationPropertyKeywordAllowed = false;
221    }
222
223    bool animationPropertyKeywordAllowed() const
224    {
225        return m_animationPropertyKeywordAllowed;
226    }
227
228    bool hasSeenAnimationPropertyKeyword() const
229    {
230        return m_hasSeenAnimationPropertyKeyword;
231    }
232
233    void sawAnimationPropertyKeyword()
234    {
235        m_hasSeenAnimationPropertyKeyword = true;
236    }
237
238private:
239    bool m_animationPropertyKeywordAllowed;
240    bool m_firstAnimationCommitted;
241    bool m_hasSeenAnimationPropertyKeyword;
242};
243
244const CSSParserContext& strictCSSParserContext()
245{
246    static NeverDestroyed<CSSParserContext> strictContext(CSSStrictMode);
247    return strictContext;
248}
249
250CSSParserContext::CSSParserContext(CSSParserMode mode, const URL& baseURL)
251    : baseURL(baseURL)
252    , mode(mode)
253    , isHTMLDocument(false)
254    , isCSSRegionsEnabled(false)
255    , isCSSCompositingEnabled(false)
256    , needsSiteSpecificQuirks(false)
257    , enforcesCSSMIMETypeInNoQuirksMode(true)
258    , useLegacyBackgroundSizeShorthandBehavior(false)
259{
260#if PLATFORM(IOS)
261    // FIXME: Force the site specific quirk below to work on iOS. Investigating other site specific quirks
262    // to see if we can enable the preference all together is to be handled by:
263    // <rdar://problem/8493309> Investigate Enabling Site Specific Quirks in MobileSafari and UIWebView
264    needsSiteSpecificQuirks = true;
265#endif
266}
267
268CSSParserContext::CSSParserContext(Document& document, const URL& baseURL, const String& charset)
269    : baseURL(baseURL.isNull() ? document.baseURL() : baseURL)
270    , charset(charset)
271    , mode(document.inQuirksMode() ? CSSQuirksMode : CSSStrictMode)
272    , isHTMLDocument(document.isHTMLDocument())
273    , isCSSRegionsEnabled(document.cssRegionsEnabled())
274    , isCSSCompositingEnabled(document.cssCompositingEnabled())
275    , needsSiteSpecificQuirks(document.settings() ? document.settings()->needsSiteSpecificQuirks() : false)
276    , enforcesCSSMIMETypeInNoQuirksMode(!document.settings() || document.settings()->enforceCSSMIMETypeInNoQuirksMode())
277    , useLegacyBackgroundSizeShorthandBehavior(document.settings() ? document.settings()->useLegacyBackgroundSizeShorthandBehavior() : false)
278{
279#if PLATFORM(IOS)
280    // FIXME: Force the site specific quirk below to work on iOS. Investigating other site specific quirks
281    // to see if we can enable the preference all together is to be handled by:
282    // <rdar://problem/8493309> Investigate Enabling Site Specific Quirks in MobileSafari and UIWebView
283    needsSiteSpecificQuirks = true;
284#endif
285}
286
287bool operator==(const CSSParserContext& a, const CSSParserContext& b)
288{
289    return a.baseURL == b.baseURL
290        && a.charset == b.charset
291        && a.mode == b.mode
292        && a.isHTMLDocument == b.isHTMLDocument
293        && a.isCSSRegionsEnabled == b.isCSSRegionsEnabled
294        && a.isCSSCompositingEnabled == b.isCSSCompositingEnabled
295        && a.needsSiteSpecificQuirks == b.needsSiteSpecificQuirks
296        && a.enforcesCSSMIMETypeInNoQuirksMode == b.enforcesCSSMIMETypeInNoQuirksMode
297        && a.useLegacyBackgroundSizeShorthandBehavior == b.useLegacyBackgroundSizeShorthandBehavior;
298}
299
300CSSParser::CSSParser(const CSSParserContext& context)
301    : m_context(context)
302    , m_important(false)
303    , m_id(CSSPropertyInvalid)
304    , m_styleSheet(0)
305#if ENABLE(CSS3_CONDITIONAL_RULES)
306    , m_supportsCondition(false)
307#endif
308    , m_selectorListForParseSelector(0)
309    , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
310    , m_inParseShorthand(0)
311    , m_currentShorthand(CSSPropertyInvalid)
312    , m_implicitShorthand(false)
313    , m_hasFontFaceOnlyValues(false)
314    , m_hadSyntacticallyValidCSSRule(false)
315    , m_logErrors(false)
316    , m_ignoreErrorsInDeclaration(false)
317    , m_defaultNamespace(starAtom)
318    , m_parsedTextPrefixLength(0)
319    , m_propertyRange(UINT_MAX, UINT_MAX)
320    , m_ruleSourceDataResult(0)
321    , m_parsingMode(NormalMode)
322    , m_is8BitSource(false)
323    , m_currentCharacter8(0)
324    , m_currentCharacter16(0)
325    , m_length(0)
326    , m_token(0)
327    , m_lineNumber(0)
328    , m_tokenStartLineNumber(0)
329    , m_lastSelectorLineNumber(0)
330    , m_allowImportRules(true)
331    , m_allowNamespaceDeclarations(true)
332#if ENABLE(CSS_DEVICE_ADAPTATION)
333    , m_inViewport(false)
334#endif
335{
336#if YYDEBUG > 0
337    cssyydebug = 1;
338#endif
339    m_tokenStart.ptr8 = 0;
340}
341
342CSSParser::~CSSParser()
343{
344    clearProperties();
345}
346
347template <typename CharacterType>
348ALWAYS_INLINE static void makeLower(const CharacterType* input, CharacterType* output, unsigned length)
349{
350    // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
351    // that can potentially change the length of the string rather than the character
352    // by character kind. If we don't need Unicode lowercasing, it would be good to
353    // simplify this function.
354
355    if (charactersAreAllASCII(input, length)) {
356        // Fast case for all-ASCII.
357        for (unsigned i = 0; i < length; i++)
358            output[i] = toASCIILower(input[i]);
359    } else {
360        for (unsigned i = 0; i < length; i++) {
361            ASSERT(u_tolower(input[i]) <= 0xFFFF);
362            output[i] = u_tolower(input[i]);
363        }
364    }
365}
366
367void CSSParserString::lower()
368{
369    if (is8Bit()) {
370        makeLower(characters8(), characters8(), length());
371        return;
372    }
373
374    makeLower(characters16(), characters16(), length());
375}
376
377void CSSParser::setupParser(const char* prefix, unsigned prefixLength, const String& string, const char* suffix, unsigned suffixLength)
378{
379    m_parsedTextPrefixLength = prefixLength;
380    unsigned stringLength = string.length();
381    unsigned length = stringLength + m_parsedTextPrefixLength + suffixLength + 1;
382    m_length = length;
383
384    if (!stringLength || string.is8Bit()) {
385        m_dataStart8 = std::make_unique<LChar[]>(length);
386        for (unsigned i = 0; i < m_parsedTextPrefixLength; i++)
387            m_dataStart8[i] = prefix[i];
388
389        if (stringLength)
390            memcpy(m_dataStart8.get() + m_parsedTextPrefixLength, string.characters8(), stringLength * sizeof(LChar));
391
392        unsigned start = m_parsedTextPrefixLength + stringLength;
393        unsigned end = start + suffixLength;
394        for (unsigned i = start; i < end; i++)
395            m_dataStart8[i] = suffix[i - start];
396
397        m_dataStart8[length - 1] = 0;
398
399        m_is8BitSource = true;
400        m_currentCharacter8 = m_dataStart8.get();
401        m_currentCharacter16 = 0;
402        setTokenStart<LChar>(m_currentCharacter8);
403        m_lexFunc = &CSSParser::realLex<LChar>;
404        return;
405    }
406
407    m_dataStart16 = std::make_unique<UChar[]>(length);
408    for (unsigned i = 0; i < m_parsedTextPrefixLength; i++)
409        m_dataStart16[i] = prefix[i];
410
411    ASSERT(stringLength);
412    memcpy(m_dataStart16.get() + m_parsedTextPrefixLength, string.characters16(), stringLength * sizeof(UChar));
413
414    unsigned start = m_parsedTextPrefixLength + stringLength;
415    unsigned end = start + suffixLength;
416    for (unsigned i = start; i < end; i++)
417        m_dataStart16[i] = suffix[i - start];
418
419    m_dataStart16[length - 1] = 0;
420
421    m_is8BitSource = false;
422    m_currentCharacter8 = 0;
423    m_currentCharacter16 = m_dataStart16.get();
424    setTokenStart<UChar>(m_currentCharacter16);
425    m_lexFunc = &CSSParser::realLex<UChar>;
426}
427
428void CSSParser::parseSheet(StyleSheetContents* sheet, const String& string, int startLineNumber, RuleSourceDataList* ruleSourceDataResult, bool logErrors)
429{
430    setStyleSheet(sheet);
431    m_defaultNamespace = starAtom; // Reset the default namespace.
432    if (ruleSourceDataResult)
433        m_currentRuleDataStack = std::make_unique<RuleSourceDataList>();
434    m_ruleSourceDataResult = ruleSourceDataResult;
435
436    m_logErrors = logErrors && sheet->singleOwnerDocument() && !sheet->baseURL().isEmpty() && sheet->singleOwnerDocument()->page();
437    m_ignoreErrorsInDeclaration = false;
438    m_lineNumber = startLineNumber;
439    setupParser("", string, "");
440    cssyyparse(this);
441    sheet->shrinkToFit();
442    m_currentRuleDataStack.reset();
443    m_ruleSourceDataResult = 0;
444    m_rule = 0;
445    m_ignoreErrorsInDeclaration = false;
446    m_logErrors = false;
447}
448
449PassRefPtr<StyleRuleBase> CSSParser::parseRule(StyleSheetContents* sheet, const String& string)
450{
451    setStyleSheet(sheet);
452    m_allowNamespaceDeclarations = false;
453    setupParser("@-webkit-rule{", string, "} ");
454    cssyyparse(this);
455    return m_rule.release();
456}
457
458PassRefPtr<StyleKeyframe> CSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string)
459{
460    setStyleSheet(sheet);
461    setupParser("@-webkit-keyframe-rule{ ", string, "} ");
462    cssyyparse(this);
463    return m_keyframe.release();
464}
465
466#if ENABLE(CSS3_CONDITIONAL_RULES)
467bool CSSParser::parseSupportsCondition(const String& string)
468{
469    m_supportsCondition = false;
470    setupParser("@-webkit-supports-condition{ ", string, "} ");
471    cssyyparse(this);
472    return m_supportsCondition;
473}
474#endif
475
476static inline bool isColorPropertyID(CSSPropertyID propertyId)
477{
478    switch (propertyId) {
479    case CSSPropertyColor:
480    case CSSPropertyBackgroundColor:
481    case CSSPropertyBorderBottomColor:
482    case CSSPropertyBorderLeftColor:
483    case CSSPropertyBorderRightColor:
484    case CSSPropertyBorderTopColor:
485    case CSSPropertyOutlineColor:
486    case CSSPropertyTextLineThroughColor:
487    case CSSPropertyTextOverlineColor:
488    case CSSPropertyTextUnderlineColor:
489    case CSSPropertyWebkitBorderAfterColor:
490    case CSSPropertyWebkitBorderBeforeColor:
491    case CSSPropertyWebkitBorderEndColor:
492    case CSSPropertyWebkitBorderStartColor:
493    case CSSPropertyWebkitColumnRuleColor:
494    case CSSPropertyWebkitTextDecorationColor:
495    case CSSPropertyWebkitTextEmphasisColor:
496    case CSSPropertyWebkitTextFillColor:
497    case CSSPropertyWebkitTextStrokeColor:
498        return true;
499    default:
500        return false;
501    }
502}
503
504static bool validPrimitiveValueColor(CSSValueID valueID, bool strict = false)
505{
506    return (valueID == CSSValueWebkitText || valueID == CSSValueCurrentcolor || valueID == CSSValueMenu
507        || (valueID >= CSSValueAlpha && valueID <= CSSValueWindowtext)
508        || (valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText && !strict));
509}
510
511static bool parseColorValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
512{
513    ASSERT(!string.isEmpty());
514    bool strict = isStrictParserMode(cssParserMode);
515    if (!isColorPropertyID(propertyId))
516        return false;
517    CSSParserString cssString;
518    cssString.init(string);
519    CSSValueID valueID = cssValueKeywordID(cssString);
520    if (validPrimitiveValueColor(valueID, strict)) {
521        RefPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID);
522        declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
523        return true;
524    }
525    RGBA32 color;
526    if (!CSSParser::fastParseColor(color, string, strict && string[0] != '#'))
527        return false;
528    RefPtr<CSSValue> value = cssValuePool().createColorValue(color);
529    declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
530    return true;
531}
532
533static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
534{
535    switch (propertyId) {
536    case CSSPropertyFontSize:
537    case CSSPropertyHeight:
538    case CSSPropertyWidth:
539    case CSSPropertyMinHeight:
540    case CSSPropertyMinWidth:
541    case CSSPropertyPaddingBottom:
542    case CSSPropertyPaddingLeft:
543    case CSSPropertyPaddingRight:
544    case CSSPropertyPaddingTop:
545    case CSSPropertyWebkitLogicalWidth:
546    case CSSPropertyWebkitLogicalHeight:
547    case CSSPropertyWebkitMinLogicalWidth:
548    case CSSPropertyWebkitMinLogicalHeight:
549    case CSSPropertyWebkitPaddingAfter:
550    case CSSPropertyWebkitPaddingBefore:
551    case CSSPropertyWebkitPaddingEnd:
552    case CSSPropertyWebkitPaddingStart:
553        acceptsNegativeNumbers = false;
554        return true;
555#if ENABLE(CSS_SHAPES)
556    case CSSPropertyWebkitShapeMargin:
557        acceptsNegativeNumbers = false;
558        return RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled();
559#endif
560    case CSSPropertyBottom:
561    case CSSPropertyLeft:
562    case CSSPropertyMarginBottom:
563    case CSSPropertyMarginLeft:
564    case CSSPropertyMarginRight:
565    case CSSPropertyMarginTop:
566    case CSSPropertyRight:
567    case CSSPropertyTop:
568    case CSSPropertyWebkitMarginAfter:
569    case CSSPropertyWebkitMarginBefore:
570    case CSSPropertyWebkitMarginEnd:
571    case CSSPropertyWebkitMarginStart:
572        acceptsNegativeNumbers = true;
573        return true;
574    default:
575        return false;
576    }
577}
578
579template <typename CharacterType>
580static inline bool parseSimpleLength(const CharacterType* characters, unsigned& length, CSSPrimitiveValue::UnitTypes& unit, double& number)
581{
582    if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
583        length -= 2;
584        unit = CSSPrimitiveValue::CSS_PX;
585    } else if (length > 1 && characters[length - 1] == '%') {
586        length -= 1;
587        unit = CSSPrimitiveValue::CSS_PERCENTAGE;
588    }
589
590    // We rely on charactersToDouble for validation as well. The function
591    // will set "ok" to "false" if the entire passed-in character range does
592    // not represent a double.
593    bool ok;
594    number = charactersToDouble(characters, length, &ok);
595    return ok;
596}
597
598static bool parseSimpleLengthValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
599{
600    ASSERT(!string.isEmpty());
601    bool acceptsNegativeNumbers;
602    if (!isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
603        return false;
604
605    unsigned length = string.length();
606    double number;
607    CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
608
609    if (string.is8Bit()) {
610        if (!parseSimpleLength(string.characters8(), length, unit, number))
611            return false;
612    } else {
613        if (!parseSimpleLength(string.characters16(), length, unit, number))
614            return false;
615    }
616
617    if (unit == CSSPrimitiveValue::CSS_NUMBER) {
618        if (number && isStrictParserMode(cssParserMode))
619            return false;
620        unit = CSSPrimitiveValue::CSS_PX;
621    }
622    if (number < 0 && !acceptsNegativeNumbers)
623        return false;
624
625    RefPtr<CSSValue> value = cssValuePool().createValue(number, unit);
626    declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
627    return true;
628}
629
630static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext)
631{
632    if (!valueID)
633        return false;
634
635    switch (propertyId) {
636    case CSSPropertyBorderCollapse: // collapse | separate | inherit
637        if (valueID == CSSValueCollapse || valueID == CSSValueSeparate)
638            return true;
639        break;
640    case CSSPropertyBorderTopStyle: // <border-style> | inherit
641    case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
642    case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
643    case CSSPropertyBorderLeftStyle:
644    case CSSPropertyWebkitBorderAfterStyle:
645    case CSSPropertyWebkitBorderBeforeStyle:
646    case CSSPropertyWebkitBorderEndStyle:
647    case CSSPropertyWebkitBorderStartStyle:
648    case CSSPropertyWebkitColumnRuleStyle:
649        if (valueID >= CSSValueNone && valueID <= CSSValueDouble)
650            return true;
651        break;
652    case CSSPropertyBoxSizing:
653         if (valueID == CSSValueBorderBox || valueID == CSSValueContentBox)
654             return true;
655         break;
656    case CSSPropertyCaptionSide: // top | bottom | left | right | inherit
657        if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom)
658            return true;
659        break;
660    case CSSPropertyClear: // none | left | right | both | inherit
661        if (valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth)
662            return true;
663        break;
664    case CSSPropertyDirection: // ltr | rtl | inherit
665        if (valueID == CSSValueLtr || valueID == CSSValueRtl)
666            return true;
667        break;
668    case CSSPropertyDisplay:
669        // inline | block | list-item | inline-block | table |
670        // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
671        // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none | inherit
672        // -webkit-flex | -webkit-inline-flex | -webkit-grid | -webkit-inline-grid
673        if ((valueID >= CSSValueInline && valueID <= CSSValueWebkitInlineFlex) || valueID == CSSValueNone)
674            return true;
675#if ENABLE(CSS_GRID_LAYOUT)
676        if (valueID == CSSValueWebkitGrid || valueID == CSSValueWebkitInlineGrid)
677            return true;
678#endif
679        break;
680
681    case CSSPropertyEmptyCells: // show | hide | inherit
682        if (valueID == CSSValueShow || valueID == CSSValueHide)
683            return true;
684        break;
685    case CSSPropertyFloat: // left | right | none | center (for buggy CSS, maps to none)
686        if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone || valueID == CSSValueCenter)
687            return true;
688        break;
689    case CSSPropertyFontStyle: // normal | italic | oblique | inherit
690        if (valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique)
691            return true;
692        break;
693    case CSSPropertyImageRendering: // auto | optimizeSpeed | optimizeQuality | -webkit-crisp-edges | -webkit-optimize-contrast
694        if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizequality
695            || valueID == CSSValueWebkitCrispEdges || valueID == CSSValueWebkitOptimizeContrast)
696            return true;
697        break;
698    case CSSPropertyListStylePosition: // inside | outside | inherit
699        if (valueID == CSSValueInside || valueID == CSSValueOutside)
700            return true;
701        break;
702    case CSSPropertyListStyleType:
703        // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
704        // for the list of supported list-style-types.
705        if ((valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone)
706            return true;
707        break;
708    case CSSPropertyObjectFit:
709        if (valueID == CSSValueFill || valueID == CSSValueContain || valueID == CSSValueCover || valueID == CSSValueNone || valueID == CSSValueScaleDown)
710            return true;
711        break;
712    case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit
713        if (valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble))
714            return true;
715        break;
716    case CSSPropertyOverflowWrap: // normal | break-word
717    case CSSPropertyWordWrap:
718        if (valueID == CSSValueNormal || valueID == CSSValueBreakWord)
719            return true;
720        break;
721    case CSSPropertyOverflowX: // visible | hidden | scroll | auto | marquee | overlay | inherit
722        if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitMarquee)
723            return true;
724        break;
725    case CSSPropertyOverflowY: // visible | hidden | scroll | auto | marquee | overlay | inherit | -webkit-paged-x | -webkit-paged-y
726        if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitMarquee || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY)
727            return true;
728        break;
729    case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit
730    case CSSPropertyPageBreakBefore:
731    case CSSPropertyWebkitColumnBreakAfter:
732    case CSSPropertyWebkitColumnBreakBefore:
733        if (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight)
734            return true;
735        break;
736    case CSSPropertyPageBreakInside: // avoid | auto | inherit
737    case CSSPropertyWebkitColumnBreakInside:
738        if (valueID == CSSValueAuto || valueID == CSSValueAvoid)
739            return true;
740        break;
741    case CSSPropertyPointerEvents:
742        // none | visiblePainted | visibleFill | visibleStroke | visible |
743        // painted | fill | stroke | auto | all | inherit
744        if (valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueStroke))
745            return true;
746        break;
747    case CSSPropertyPosition: // static | relative | absolute | fixed | sticky | inherit
748        if (valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed || valueID == CSSValueWebkitSticky)
749            return true;
750        break;
751    case CSSPropertyResize: // none | both | horizontal | vertical | auto
752        if (valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto)
753            return true;
754        break;
755    case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit
756        if (valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation)
757            return true;
758        break;
759    case CSSPropertyTableLayout: // auto | fixed | inherit
760        if (valueID == CSSValueAuto || valueID == CSSValueFixed)
761            return true;
762        break;
763    case CSSPropertyTextLineThroughMode:
764    case CSSPropertyTextOverlineMode:
765    case CSSPropertyTextUnderlineMode:
766        if (valueID == CSSValueContinuous || valueID == CSSValueSkipWhiteSpace)
767            return true;
768        break;
769    case CSSPropertyTextLineThroughStyle:
770    case CSSPropertyTextOverlineStyle:
771    case CSSPropertyTextUnderlineStyle:
772        if (valueID == CSSValueNone || valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDashed || valueID == CSSValueDotDash || valueID == CSSValueDotDotDash || valueID == CSSValueWave)
773            return true;
774        break;
775    case CSSPropertyTextOverflow: // clip | ellipsis
776        if (valueID == CSSValueClip || valueID == CSSValueEllipsis)
777            return true;
778        break;
779    case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
780        if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision)
781            return true;
782        break;
783    case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit
784        if ((valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone)
785            return true;
786        break;
787    case CSSPropertyVisibility: // visible | hidden | collapse | inherit
788        if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse)
789            return true;
790        break;
791    case CSSPropertyWebkitAppearance:
792        if ((valueID >= CSSValueCheckbox && valueID <= CSSValueTextarea) || valueID == CSSValueNone)
793            return true;
794        break;
795    case CSSPropertyWebkitBackfaceVisibility:
796        if (valueID == CSSValueVisible || valueID == CSSValueHidden)
797            return true;
798        break;
799#if ENABLE(CSS_COMPOSITING)
800    case CSSPropertyMixBlendMode:
801        if (parserContext.isCSSCompositingEnabled && (valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen
802            || valueID == CSSValueOverlay || valueID == CSSValueDarken || valueID == CSSValueLighten ||  valueID == CSSValueColorDodge
803            || valueID == CSSValueColorBurn || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference
804            || valueID == CSSValueExclusion))
805            return true;
806        break;
807    case CSSPropertyIsolation:
808        if (parserContext.isCSSCompositingEnabled && (valueID == CSSValueAuto || valueID == CSSValueIsolate))
809            return true;
810        break;
811#endif
812    case CSSPropertyWebkitBorderFit:
813        if (valueID == CSSValueBorder || valueID == CSSValueLines)
814            return true;
815        break;
816    case CSSPropertyWebkitBoxAlign:
817        if (valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline)
818            return true;
819        break;
820#if ENABLE(CSS_BOX_DECORATION_BREAK)
821    case CSSPropertyWebkitBoxDecorationBreak:
822         if (valueID == CSSValueClone || valueID == CSSValueSlice)
823             return true;
824         break;
825#endif
826    case CSSPropertyWebkitBoxDirection:
827        if (valueID == CSSValueNormal || valueID == CSSValueReverse)
828            return true;
829        break;
830    case CSSPropertyWebkitBoxLines:
831        if (valueID == CSSValueSingle || valueID == CSSValueMultiple)
832                return true;
833        break;
834    case CSSPropertyWebkitBoxOrient:
835        if (valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis)
836            return true;
837        break;
838    case CSSPropertyWebkitBoxPack:
839        if (valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify)
840            return true;
841        break;
842    case CSSPropertyWebkitColorCorrection:
843        if (valueID == CSSValueSrgb || valueID == CSSValueDefault)
844            return true;
845        break;
846    case CSSPropertyWebkitColumnFill:
847        if (valueID == CSSValueAuto || valueID == CSSValueBalance)
848            return true;
849        break;
850    case CSSPropertyWebkitAlignContent:
851        // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
852        if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch)
853            return true;
854        break;
855    case CSSPropertyWebkitAlignItems:
856        // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
857        if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
858            return true;
859        break;
860    case CSSPropertyWebkitAlignSelf:
861        // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
862        if (valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
863            return true;
864        break;
865    case CSSPropertyWebkitFlexDirection:
866        if (valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse)
867            return true;
868        break;
869    case CSSPropertyWebkitFlexWrap:
870        if (valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse)
871             return true;
872        break;
873    case CSSPropertyWebkitJustifyContent:
874        // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
875        if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround)
876            return true;
877        break;
878    case CSSPropertyWebkitJustifySelf:
879        if (valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
880            return true;
881        break;
882    case CSSPropertyWebkitFontKerning:
883        if (valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone)
884            return true;
885        break;
886    case CSSPropertyWebkitFontSmoothing:
887        if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased)
888            return true;
889        break;
890    case CSSPropertyWebkitHyphens:
891        if (valueID == CSSValueNone || valueID == CSSValueManual || valueID == CSSValueAuto)
892            return true;
893        break;
894    case CSSPropertyWebkitLineAlign:
895        if (valueID == CSSValueNone || valueID == CSSValueEdges)
896            return true;
897        break;
898    case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
899        if (valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace)
900            return true;
901        break;
902    case CSSPropertyWebkitLineSnap:
903        if (valueID == CSSValueNone || valueID == CSSValueBaseline || valueID == CSSValueContain)
904            return true;
905        break;
906    case CSSPropertyWebkitMarginAfterCollapse:
907    case CSSPropertyWebkitMarginBeforeCollapse:
908    case CSSPropertyWebkitMarginBottomCollapse:
909    case CSSPropertyWebkitMarginTopCollapse:
910        if (valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard)
911            return true;
912        break;
913    case CSSPropertyWebkitMarqueeDirection:
914        if (valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
915            || valueID == CSSValueUp || valueID == CSSValueAuto)
916            return true;
917        break;
918    case CSSPropertyWebkitMarqueeStyle:
919        if (valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate)
920            return true;
921        break;
922    case CSSPropertyWebkitNbspMode: // normal | space
923        if (valueID == CSSValueNormal || valueID == CSSValueSpace)
924            return true;
925        break;
926#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
927    case CSSPropertyWebkitOverflowScrolling:
928        if (valueID == CSSValueAuto || valueID == CSSValueTouch)
929            return true;
930        break;
931#endif
932    case CSSPropertyWebkitPrintColorAdjust:
933        if (valueID == CSSValueExact || valueID == CSSValueEconomy)
934            return true;
935        break;
936#if ENABLE(CSS_REGIONS)
937    case CSSPropertyWebkitRegionBreakAfter:
938    case CSSPropertyWebkitRegionBreakBefore:
939        if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight))
940            return true;
941        break;
942    case CSSPropertyWebkitRegionBreakInside:
943        if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueAvoid))
944            return true;
945        break;
946    case CSSPropertyWebkitRegionFragment:
947        if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueBreak))
948            return true;
949        break;
950#endif
951    case CSSPropertyWebkitRtlOrdering:
952        if (valueID == CSSValueLogical || valueID == CSSValueVisual)
953            return true;
954        break;
955
956    case CSSPropertyWebkitRubyPosition:
957        if (valueID == CSSValueBefore || valueID == CSSValueAfter)
958            return true;
959        break;
960
961#if ENABLE(CSS3_TEXT)
962    case CSSPropertyWebkitTextAlignLast:
963        // auto | start | end | left | right | center | justify
964        if ((valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto)
965            return true;
966        break;
967#endif // CSS3_TEXT
968    case CSSPropertyWebkitTextCombine:
969        if (valueID == CSSValueNone || valueID == CSSValueHorizontal)
970            return true;
971        break;
972#if ENABLE(CSS3_TEXT)
973    case CSSPropertyWebkitTextJustify:
974        // auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida
975        if ((valueID >= CSSValueInterWord && valueID <= CSSValueKashida) || valueID == CSSValueAuto || valueID == CSSValueNone)
976            return true;
977        break;
978#endif // CSS3_TEXT
979    case CSSPropertyWebkitTextSecurity:
980        // disc | circle | square | none | inherit
981        if (valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone)
982            return true;
983        break;
984#if ENABLE(IOS_TEXT_AUTOSIZING)
985    case CSSPropertyWebkitTextSizeAdjust:
986        if (valueID == CSSValueAuto || valueID == CSSValueNone)
987            return true;
988        break;
989#endif
990    case CSSPropertyWebkitTransformStyle:
991        if (valueID == CSSValueFlat || valueID == CSSValuePreserve3d)
992            return true;
993        break;
994    case CSSPropertyWebkitUserDrag: // auto | none | element
995        if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement)
996            return true;
997        break;
998    case CSSPropertyWebkitUserModify: // read-only | read-write
999        if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly)
1000            return true;
1001        break;
1002    case CSSPropertyWebkitUserSelect: // auto | none | text | all
1003        if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll)
1004            return true;
1005        break;
1006    case CSSPropertyWebkitWritingMode:
1007        if (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
1008            return true;
1009        break;
1010    case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit
1011        if (valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap)
1012            return true;
1013        break;
1014    case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
1015        if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord)
1016            return true;
1017        break;
1018    default:
1019        ASSERT_NOT_REACHED();
1020        return false;
1021    }
1022    return false;
1023}
1024
1025static inline bool isKeywordPropertyID(CSSPropertyID propertyId)
1026{
1027    switch (propertyId) {
1028    case CSSPropertyBorderBottomStyle:
1029    case CSSPropertyBorderCollapse:
1030    case CSSPropertyBorderLeftStyle:
1031    case CSSPropertyBorderRightStyle:
1032    case CSSPropertyBorderTopStyle:
1033    case CSSPropertyBoxSizing:
1034    case CSSPropertyCaptionSide:
1035    case CSSPropertyClear:
1036    case CSSPropertyDirection:
1037    case CSSPropertyDisplay:
1038    case CSSPropertyEmptyCells:
1039    case CSSPropertyFloat:
1040    case CSSPropertyFontStyle:
1041    case CSSPropertyImageRendering:
1042    case CSSPropertyListStylePosition:
1043    case CSSPropertyListStyleType:
1044    case CSSPropertyObjectFit:
1045    case CSSPropertyOutlineStyle:
1046    case CSSPropertyOverflowWrap:
1047    case CSSPropertyOverflowX:
1048    case CSSPropertyOverflowY:
1049    case CSSPropertyPageBreakAfter:
1050    case CSSPropertyPageBreakBefore:
1051    case CSSPropertyPageBreakInside:
1052    case CSSPropertyPointerEvents:
1053    case CSSPropertyPosition:
1054    case CSSPropertyResize:
1055    case CSSPropertySpeak:
1056    case CSSPropertyTableLayout:
1057    case CSSPropertyTextLineThroughMode:
1058    case CSSPropertyTextLineThroughStyle:
1059    case CSSPropertyTextOverflow:
1060    case CSSPropertyTextOverlineMode:
1061    case CSSPropertyTextOverlineStyle:
1062    case CSSPropertyTextRendering:
1063    case CSSPropertyTextTransform:
1064    case CSSPropertyTextUnderlineMode:
1065    case CSSPropertyTextUnderlineStyle:
1066    case CSSPropertyVisibility:
1067    case CSSPropertyWebkitAppearance:
1068#if ENABLE(CSS_COMPOSITING)
1069    case CSSPropertyMixBlendMode:
1070    case CSSPropertyIsolation:
1071#endif
1072    case CSSPropertyWebkitBackfaceVisibility:
1073    case CSSPropertyWebkitBorderAfterStyle:
1074    case CSSPropertyWebkitBorderBeforeStyle:
1075    case CSSPropertyWebkitBorderEndStyle:
1076    case CSSPropertyWebkitBorderFit:
1077    case CSSPropertyWebkitBorderStartStyle:
1078    case CSSPropertyWebkitBoxAlign:
1079#if ENABLE(CSS_BOX_DECORATION_BREAK)
1080    case CSSPropertyWebkitBoxDecorationBreak:
1081#endif
1082    case CSSPropertyWebkitBoxDirection:
1083    case CSSPropertyWebkitBoxLines:
1084    case CSSPropertyWebkitBoxOrient:
1085    case CSSPropertyWebkitBoxPack:
1086    case CSSPropertyWebkitColorCorrection:
1087    case CSSPropertyWebkitColumnBreakAfter:
1088    case CSSPropertyWebkitColumnBreakBefore:
1089    case CSSPropertyWebkitColumnBreakInside:
1090    case CSSPropertyWebkitColumnFill:
1091    case CSSPropertyWebkitColumnRuleStyle:
1092    case CSSPropertyWebkitAlignContent:
1093    case CSSPropertyWebkitAlignItems:
1094    case CSSPropertyWebkitAlignSelf:
1095    case CSSPropertyWebkitFlexDirection:
1096    case CSSPropertyWebkitFlexWrap:
1097    case CSSPropertyWebkitJustifyContent:
1098    case CSSPropertyWebkitFontKerning:
1099    case CSSPropertyWebkitFontSmoothing:
1100    case CSSPropertyWebkitHyphens:
1101    case CSSPropertyWebkitLineAlign:
1102    case CSSPropertyWebkitLineBreak:
1103    case CSSPropertyWebkitLineSnap:
1104    case CSSPropertyWebkitMarginAfterCollapse:
1105    case CSSPropertyWebkitMarginBeforeCollapse:
1106    case CSSPropertyWebkitMarginBottomCollapse:
1107    case CSSPropertyWebkitMarginTopCollapse:
1108    case CSSPropertyWebkitMarqueeDirection:
1109    case CSSPropertyWebkitMarqueeStyle:
1110    case CSSPropertyWebkitNbspMode:
1111#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
1112    case CSSPropertyWebkitOverflowScrolling:
1113#endif
1114    case CSSPropertyWebkitPrintColorAdjust:
1115#if ENABLE(CSS_REGIONS)
1116    case CSSPropertyWebkitRegionBreakAfter:
1117    case CSSPropertyWebkitRegionBreakBefore:
1118    case CSSPropertyWebkitRegionBreakInside:
1119    case CSSPropertyWebkitRegionFragment:
1120#endif
1121    case CSSPropertyWebkitRtlOrdering:
1122    case CSSPropertyWebkitRubyPosition:
1123#if ENABLE(CSS3_TEXT)
1124    case CSSPropertyWebkitTextAlignLast:
1125#endif // CSS3_TEXT
1126    case CSSPropertyWebkitTextCombine:
1127#if ENABLE(CSS3_TEXT)
1128    case CSSPropertyWebkitTextJustify:
1129#endif // CSS3_TEXT
1130    case CSSPropertyWebkitTextSecurity:
1131    case CSSPropertyWebkitTransformStyle:
1132    case CSSPropertyWebkitUserDrag:
1133    case CSSPropertyWebkitUserModify:
1134    case CSSPropertyWebkitUserSelect:
1135    case CSSPropertyWebkitWritingMode:
1136    case CSSPropertyWhiteSpace:
1137    case CSSPropertyWordBreak:
1138    case CSSPropertyWordWrap:
1139        return true;
1140    default:
1141        return false;
1142    }
1143}
1144
1145static bool parseKeywordValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext)
1146{
1147    ASSERT(!string.isEmpty());
1148
1149    if (!isKeywordPropertyID(propertyId)) {
1150        // All properties accept the values of "initial" and "inherit".
1151        String lowerCaseString = string.lower();
1152        if (lowerCaseString != "initial" && lowerCaseString != "inherit")
1153            return false;
1154
1155        // Parse initial/inherit shorthands using the CSSParser.
1156        if (shorthandForProperty(propertyId).length())
1157            return false;
1158    }
1159
1160    CSSParserString cssString;
1161    cssString.init(string);
1162    CSSValueID valueID = cssValueKeywordID(cssString);
1163
1164    if (!valueID)
1165        return false;
1166
1167    RefPtr<CSSValue> value;
1168    if (valueID == CSSValueInherit)
1169        value = cssValuePool().createInheritedValue();
1170    else if (valueID == CSSValueInitial)
1171        value = cssValuePool().createExplicitInitialValue();
1172    else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext))
1173        value = cssValuePool().createIdentifierValue(valueID);
1174    else
1175        return false;
1176
1177    declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
1178    return true;
1179}
1180
1181template <typename CharacterType>
1182static bool parseTransformArguments(WebKitCSSTransformValue* transformValue, CharacterType* characters, unsigned length, unsigned start, unsigned expectedCount)
1183{
1184    while (expectedCount) {
1185        size_t end = WTF::find(characters, length, expectedCount == 1 ? ')' : ',', start);
1186        if (end == notFound || (expectedCount == 1 && end != length - 1))
1187            return false;
1188        unsigned argumentLength = end - start;
1189        CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
1190        double number;
1191        if (!parseSimpleLength(characters + start, argumentLength, unit, number))
1192            return false;
1193        if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER))
1194            return false;
1195        transformValue->append(cssValuePool().createValue(number, unit));
1196        start = end + 1;
1197        --expectedCount;
1198    }
1199    return true;
1200}
1201
1202static bool parseTranslateTransformValue(MutableStyleProperties* properties, CSSPropertyID propertyID, const String& string, bool important)
1203{
1204    if (propertyID != CSSPropertyWebkitTransform)
1205        return false;
1206    static const unsigned shortestValidTransformStringLength = 12;
1207    static const unsigned likelyMultipartTransformStringLengthCutoff = 32;
1208    if (string.length() < shortestValidTransformStringLength || string.length() > likelyMultipartTransformStringLengthCutoff)
1209        return false;
1210    if (!string.startsWith("translate", false))
1211        return false;
1212    UChar c9 = toASCIILower(string[9]);
1213    UChar c10 = toASCIILower(string[10]);
1214
1215    WebKitCSSTransformValue::TransformOperationType transformType;
1216    unsigned expectedArgumentCount = 1;
1217    unsigned argumentStart = 11;
1218    if (c9 == 'x' && c10 == '(')
1219        transformType = WebKitCSSTransformValue::TranslateXTransformOperation;
1220    else if (c9 == 'y' && c10 == '(')
1221        transformType = WebKitCSSTransformValue::TranslateYTransformOperation;
1222    else if (c9 == 'z' && c10 == '(')
1223        transformType = WebKitCSSTransformValue::TranslateZTransformOperation;
1224    else if (c9 == '(') {
1225        transformType = WebKitCSSTransformValue::TranslateTransformOperation;
1226        expectedArgumentCount = 2;
1227        argumentStart = 10;
1228    } else if (c9 == '3' && c10 == 'd' && string[11] == '(') {
1229        transformType = WebKitCSSTransformValue::Translate3DTransformOperation;
1230        expectedArgumentCount = 3;
1231        argumentStart = 12;
1232    } else
1233        return false;
1234
1235    RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(transformType);
1236    bool success;
1237    if (string.is8Bit())
1238        success = parseTransformArguments(transformValue.get(), string.characters8(), string.length(), argumentStart, expectedArgumentCount);
1239    else
1240        success = parseTransformArguments(transformValue.get(), string.characters16(), string.length(), argumentStart, expectedArgumentCount);
1241    if (!success)
1242        return false;
1243    RefPtr<CSSValueList> result = CSSValueList::createSpaceSeparated();
1244    result->append(transformValue.release());
1245    properties->addParsedProperty(CSSProperty(CSSPropertyWebkitTransform, result.release(), important));
1246    return true;
1247}
1248
1249PassRefPtr<CSSValueList> CSSParser::parseFontFaceValue(const AtomicString& string)
1250{
1251    if (string.isEmpty())
1252        return 0;
1253    RefPtr<MutableStyleProperties> dummyStyle = MutableStyleProperties::create();
1254    if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, CSSQuirksMode, 0))
1255        return 0;
1256
1257    RefPtr<CSSValue> fontFamily = dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily);
1258    if (!fontFamily->isValueList())
1259        return 0; // FIXME: "initial" and "inherit" should be parsed as font names in the face attribute.
1260    return static_pointer_cast<CSSValueList>(fontFamily.release());
1261}
1262
1263bool CSSParser::parseValue(MutableStyleProperties* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
1264{
1265    ASSERT(!string.isEmpty());
1266    if (parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode))
1267        return true;
1268    if (parseColorValue(declaration, propertyID, string, important, cssParserMode))
1269        return true;
1270
1271    CSSParserContext context(cssParserMode);
1272    if (contextStyleSheet) {
1273        context = contextStyleSheet->parserContext();
1274        context.mode = cssParserMode;
1275    }
1276
1277    if (parseKeywordValue(declaration, propertyID, string, important, context))
1278        return true;
1279    if (parseTranslateTransformValue(declaration, propertyID, string, important))
1280        return true;
1281
1282    CSSParser parser(context);
1283    return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet);
1284}
1285
1286bool CSSParser::parseValue(MutableStyleProperties* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet)
1287{
1288    setStyleSheet(contextStyleSheet);
1289
1290    setupParser("@-webkit-value{", string, "} ");
1291
1292    m_id = propertyID;
1293    m_important = important;
1294
1295    cssyyparse(this);
1296
1297    m_rule = 0;
1298
1299    bool ok = false;
1300    if (m_hasFontFaceOnlyValues)
1301        deleteFontFaceOnlyValues();
1302    if (!m_parsedProperties.isEmpty()) {
1303        ok = true;
1304        declaration->addParsedProperties(m_parsedProperties);
1305        clearProperties();
1306    }
1307
1308    return ok;
1309}
1310
1311// The color will only be changed when string contains a valid CSS color, so callers
1312// can set it to a default color and ignore the boolean result.
1313bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
1314{
1315    // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
1316    if (fastParseColor(color, string, strict))
1317        return true;
1318
1319    CSSParser parser(CSSStrictMode);
1320
1321    // In case the fast-path parser didn't understand the color, try the full parser.
1322    if (!parser.parseColor(string))
1323        return false;
1324
1325    CSSValue* value = parser.m_parsedProperties.first().value();
1326    if (!value->isPrimitiveValue())
1327        return false;
1328
1329    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
1330    if (!primitiveValue->isRGBColor())
1331        return false;
1332
1333    color = primitiveValue->getRGBA32Value();
1334    return true;
1335}
1336
1337bool CSSParser::parseColor(const String& string)
1338{
1339    setupParser("@-webkit-decls{color:", string, "} ");
1340    cssyyparse(this);
1341    m_rule = 0;
1342
1343    return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor;
1344}
1345
1346bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document)
1347{
1348    if (!document || !document->page())
1349        return false;
1350
1351    CSSParserString cssColor;
1352    cssColor.init(string);
1353    CSSValueID id = cssValueKeywordID(cssColor);
1354    if (!validPrimitiveValueColor(id))
1355        return false;
1356
1357    Color parsedColor = document->page()->theme().systemColor(id);
1358    if (!parsedColor.isValid())
1359        return false;
1360
1361    color = parsedColor.rgb();
1362    return true;
1363}
1364
1365void CSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
1366{
1367    m_selectorListForParseSelector = &selectorList;
1368
1369    setupParser("@-webkit-selector{", string, "}");
1370
1371    cssyyparse(this);
1372
1373    m_selectorListForParseSelector = 0;
1374}
1375
1376PassRef<ImmutableStyleProperties> CSSParser::parseInlineStyleDeclaration(const String& string, Element* element)
1377{
1378    CSSParserContext context = element->document().elementSheet().contents().parserContext();
1379    context.mode = strictToCSSParserMode(element->isHTMLElement() && !element->document().inQuirksMode());
1380    return CSSParser(context).parseDeclaration(string, &element->document().elementSheet().contents());
1381}
1382
1383PassRef<ImmutableStyleProperties> CSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet)
1384{
1385    setStyleSheet(contextStyleSheet);
1386
1387    setupParser("@-webkit-decls{", string, "} ");
1388    cssyyparse(this);
1389    m_rule = 0;
1390
1391    if (m_hasFontFaceOnlyValues)
1392        deleteFontFaceOnlyValues();
1393
1394    PassRef<ImmutableStyleProperties> style = createStyleProperties();
1395    clearProperties();
1396    return style;
1397}
1398
1399
1400bool CSSParser::parseDeclaration(MutableStyleProperties* declaration, const String& string, PassRefPtr<CSSRuleSourceData> prpRuleSourceData, StyleSheetContents* contextStyleSheet)
1401{
1402    // Length of the "@-webkit-decls{" prefix.
1403    static const unsigned prefixLength = 15;
1404
1405    setStyleSheet(contextStyleSheet);
1406
1407    RefPtr<CSSRuleSourceData> ruleSourceData = prpRuleSourceData;
1408    if (ruleSourceData) {
1409        m_currentRuleDataStack = std::make_unique<RuleSourceDataList>();
1410        m_currentRuleDataStack->append(ruleSourceData);
1411    }
1412
1413    setupParser("@-webkit-decls{", string, "} ");
1414    cssyyparse(this);
1415    m_rule = 0;
1416
1417    bool ok = false;
1418    if (m_hasFontFaceOnlyValues)
1419        deleteFontFaceOnlyValues();
1420    if (!m_parsedProperties.isEmpty()) {
1421        ok = true;
1422        declaration->addParsedProperties(m_parsedProperties);
1423        clearProperties();
1424    }
1425
1426    if (ruleSourceData) {
1427        ASSERT(m_currentRuleDataStack->size() == 1);
1428        ruleSourceData->ruleBodyRange.start = 0;
1429        ruleSourceData->ruleBodyRange.end = string.length();
1430        for (size_t i = 0, size = ruleSourceData->styleSourceData->propertyData.size(); i < size; ++i) {
1431            CSSPropertySourceData& propertyData = ruleSourceData->styleSourceData->propertyData.at(i);
1432            propertyData.range.start -= prefixLength;
1433            propertyData.range.end -= prefixLength;
1434        }
1435
1436        fixUnparsedPropertyRanges(ruleSourceData.get());
1437        m_currentRuleDataStack.reset();
1438    }
1439
1440    return ok;
1441}
1442
1443std::unique_ptr<MediaQuery> CSSParser::parseMediaQuery(const String& string)
1444{
1445    if (string.isEmpty())
1446        return nullptr;
1447
1448    ASSERT(!m_mediaQuery);
1449
1450    // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
1451    // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
1452    setupParser("@-webkit-mediaquery ", string, "} ");
1453    cssyyparse(this);
1454
1455    return WTF::move(m_mediaQuery);
1456}
1457
1458#if ENABLE(PICTURE_SIZES)
1459std::unique_ptr<SourceSizeList> CSSParser::parseSizesAttribute(const String& string)
1460{
1461    if (string.isEmpty())
1462        return nullptr;
1463
1464    ASSERT(!m_sourceSizeList.get());
1465
1466    setupParser("@-webkit-sizesattr ", string, "}");
1467    cssyyparse(this);
1468
1469    return WTF::move(m_sourceSizeList);
1470}
1471#endif
1472
1473static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, std::bitset<numCSSProperties>& seenProperties)
1474{
1475    // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
1476    for (int i = input.size() - 1; i >= 0; --i) {
1477        const CSSProperty& property = input[i];
1478        if (property.isImportant() != important)
1479            continue;
1480        const unsigned propertyIDIndex = property.id() - firstCSSProperty;
1481        ASSERT(propertyIDIndex < seenProperties.size());
1482        if (seenProperties[propertyIDIndex])
1483            continue;
1484        seenProperties.set(propertyIDIndex);
1485        output[--unusedEntries] = property;
1486    }
1487}
1488
1489PassRef<ImmutableStyleProperties> CSSParser::createStyleProperties()
1490{
1491    std::bitset<numCSSProperties> seenProperties;
1492    size_t unusedEntries = m_parsedProperties.size();
1493    Vector<CSSProperty, 256> results(unusedEntries);
1494
1495    // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found.
1496    filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties);
1497    filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties);
1498    if (unusedEntries)
1499        results.remove(0, unusedEntries);
1500
1501    return ImmutableStyleProperties::create(results.data(), results.size(), m_context.mode);
1502}
1503
1504void CSSParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
1505{
1506    RefPtr<CSSValue> val = value.get();
1507    addProperty(propId, value, important, implicit);
1508
1509    CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId);
1510    if (prefixingVariant == propId)
1511        return;
1512
1513    if (m_currentShorthand) {
1514        // We can't use ShorthandScope here as we can already be inside one (e.g we are parsing CSSTransition).
1515        m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
1516        addProperty(prefixingVariant, val.release(), important, implicit);
1517        m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
1518    } else
1519        addProperty(prefixingVariant, val.release(), important, implicit);
1520}
1521
1522void CSSParser::addProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
1523{
1524    // This property doesn't belong to a shorthand or is a CSS variable (which will be resolved later).
1525    if (!m_currentShorthand) {
1526        m_parsedProperties.append(CSSProperty(propId, value, important, false, CSSPropertyInvalid, m_implicitShorthand || implicit));
1527        return;
1528    }
1529
1530    Vector<StylePropertyShorthand> shorthands = matchingShorthandsForLonghand(propId);
1531    if (shorthands.size() == 1)
1532        m_parsedProperties.append(CSSProperty(propId, value, important, true, CSSPropertyInvalid, m_implicitShorthand || implicit));
1533    else
1534        m_parsedProperties.append(CSSProperty(propId, value, important, true, indexOfShorthandForLonghand(m_currentShorthand, shorthands), m_implicitShorthand || implicit));
1535}
1536
1537void CSSParser::rollbackLastProperties(int num)
1538{
1539    ASSERT(num >= 0);
1540    ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
1541    m_parsedProperties.shrink(m_parsedProperties.size() - num);
1542}
1543
1544void CSSParser::clearProperties()
1545{
1546    m_parsedProperties.clear();
1547    m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
1548    m_hasFontFaceOnlyValues = false;
1549}
1550
1551URL CSSParser::completeURL(const CSSParserContext& context, const String& url)
1552{
1553    if (url.isNull())
1554        return URL();
1555    if (context.charset.isEmpty())
1556        return URL(context.baseURL, url);
1557    return URL(context.baseURL, url, context.charset);
1558}
1559
1560URL CSSParser::completeURL(const String& url) const
1561{
1562    return completeURL(m_context, url);
1563}
1564
1565bool CSSParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc)
1566{
1567    bool mustBeNonNegative = unitflags & FNonNeg;
1568
1569    if (!parseCalculation(value, mustBeNonNegative ? CalculationRangeNonNegative : CalculationRangeAll))
1570        return false;
1571
1572    bool b = false;
1573    switch (m_parsedCalculation->category()) {
1574    case CalcNumber:
1575        b = (unitflags & FNumber);
1576        if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
1577            b = true;
1578        if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1579            b = false;
1580        break;
1581    case CalcLength:
1582        b = (unitflags & FLength);
1583        break;
1584    case CalcPercent:
1585        b = (unitflags & FPercent);
1586        if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1587            b = false;
1588        break;
1589    case CalcPercentLength:
1590        b = (unitflags & FPercent) && (unitflags & FLength);
1591        break;
1592    case CalcPercentNumber:
1593        b = (unitflags & FPercent) && (unitflags & FNumber);
1594        break;
1595    case CalcAngle:
1596        b = (unitflags & FAngle);
1597        break;
1598    case CalcTime:
1599        b = (unitflags & FTime);
1600        break;
1601    case CalcFrequency:
1602        b = (unitflags & FFrequency);
1603        break;
1604    case CalcOther:
1605        break;
1606    }
1607    if (!b || releaseCalc == ReleaseParsedCalcValue)
1608        m_parsedCalculation.release();
1609    return b;
1610}
1611
1612inline bool CSSParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
1613{
1614    // Qirks mode and svg presentation attributes accept unit less values.
1615    return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || cssParserMode == CSSQuirksMode || cssParserMode == SVGAttributeMode);
1616}
1617
1618bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
1619{
1620    if (isCalculation(value))
1621        return validCalculationUnit(value, unitflags, releaseCalc);
1622
1623    bool b = false;
1624    switch (value->unit) {
1625    case CSSPrimitiveValue::CSS_NUMBER:
1626        b = (unitflags & FNumber);
1627        if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
1628            value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
1629                          ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
1630            b = true;
1631        }
1632        if (!b && (unitflags & FInteger) && value->isInt)
1633            b = true;
1634        if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0)
1635            b = true;
1636        break;
1637    case CSSPrimitiveValue::CSS_PERCENTAGE:
1638        b = (unitflags & FPercent);
1639        break;
1640    case CSSParserValue::Q_EMS:
1641    case CSSPrimitiveValue::CSS_EMS:
1642    case CSSPrimitiveValue::CSS_REMS:
1643    case CSSPrimitiveValue::CSS_CHS:
1644    case CSSPrimitiveValue::CSS_EXS:
1645    case CSSPrimitiveValue::CSS_PX:
1646    case CSSPrimitiveValue::CSS_CM:
1647    case CSSPrimitiveValue::CSS_MM:
1648    case CSSPrimitiveValue::CSS_IN:
1649    case CSSPrimitiveValue::CSS_PT:
1650    case CSSPrimitiveValue::CSS_PC:
1651    case CSSPrimitiveValue::CSS_VW:
1652    case CSSPrimitiveValue::CSS_VH:
1653    case CSSPrimitiveValue::CSS_VMIN:
1654    case CSSPrimitiveValue::CSS_VMAX:
1655        b = (unitflags & FLength);
1656        break;
1657    case CSSPrimitiveValue::CSS_MS:
1658    case CSSPrimitiveValue::CSS_S:
1659        b = (unitflags & FTime);
1660        break;
1661    case CSSPrimitiveValue::CSS_DEG:
1662    case CSSPrimitiveValue::CSS_RAD:
1663    case CSSPrimitiveValue::CSS_GRAD:
1664    case CSSPrimitiveValue::CSS_TURN:
1665        b = (unitflags & FAngle);
1666        break;
1667#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
1668    case CSSPrimitiveValue::CSS_DPPX:
1669    case CSSPrimitiveValue::CSS_DPI:
1670    case CSSPrimitiveValue::CSS_DPCM:
1671        b = (unitflags & FResolution);
1672        break;
1673#endif
1674    case CSSPrimitiveValue::CSS_HZ:
1675    case CSSPrimitiveValue::CSS_KHZ:
1676    case CSSPrimitiveValue::CSS_DIMENSION:
1677    default:
1678        break;
1679    }
1680    if (b && unitflags & FNonNeg && value->fValue < 0)
1681        b = false;
1682    return b;
1683}
1684
1685inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveNumericValue(CSSParserValue* value)
1686{
1687    if (m_parsedCalculation) {
1688        ASSERT(isCalculation(value));
1689        return CSSPrimitiveValue::create(m_parsedCalculation.release());
1690    }
1691
1692#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
1693    ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1694        || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
1695        || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
1696        || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
1697#else
1698    ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1699        || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
1700        || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX));
1701#endif
1702    return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
1703}
1704
1705inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveStringValue(CSSParserValue* value)
1706{
1707    ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
1708    return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
1709}
1710
1711static inline bool isComma(CSSParserValue* value)
1712{
1713    return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
1714}
1715
1716static inline bool isForwardSlashOperator(CSSParserValue* value)
1717{
1718    ASSERT(value);
1719    return value->unit == CSSParserValue::Operator && value->iValue == '/';
1720}
1721
1722bool CSSParser::validWidth(CSSParserValue* value)
1723{
1724    int id = value->id;
1725    if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
1726        return true;
1727    return !id && validUnit(value, FLength | FPercent | FNonNeg);
1728}
1729
1730// FIXME: Combine this with validWidth when we support fit-content, et al, for heights.
1731bool CSSParser::validHeight(CSSParserValue* value)
1732{
1733    int id = value->id;
1734    if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
1735        return true;
1736    return !id && validUnit(value, FLength | FPercent | FNonNeg);
1737}
1738
1739inline PassRefPtr<CSSPrimitiveValue> CSSParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value)
1740{
1741    if (identifier)
1742        return cssValuePool().createIdentifierValue(identifier);
1743    if (value->unit == CSSPrimitiveValue::CSS_STRING)
1744        return createPrimitiveStringValue(value);
1745    if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1746        return createPrimitiveNumericValue(value);
1747    if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
1748        return createPrimitiveNumericValue(value);
1749    if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
1750        return createPrimitiveNumericValue(value);
1751#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
1752    if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
1753        return createPrimitiveNumericValue(value);
1754#endif
1755    if (value->unit >= CSSParserValue::Q_EMS)
1756        return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
1757    if (isCalculation(value))
1758        return CSSPrimitiveValue::create(m_parsedCalculation.release());
1759
1760    return 0;
1761}
1762
1763void CSSParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtr<CSSValue> prpValue, bool important)
1764{
1765    const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
1766    unsigned shorthandLength = shorthand.length();
1767    if (!shorthandLength) {
1768        addProperty(propId, prpValue, important);
1769        return;
1770    }
1771
1772    RefPtr<CSSValue> value = prpValue;
1773    ShorthandScope scope(this, propId);
1774    const CSSPropertyID* longhands = shorthand.properties();
1775    for (unsigned i = 0; i < shorthandLength; ++i)
1776        addProperty(longhands[i], value, important);
1777}
1778
1779bool CSSParser::parseValue(CSSPropertyID propId, bool important)
1780{
1781    if (!m_valueList)
1782        return false;
1783
1784    CSSParserValue* value = m_valueList->current();
1785
1786    if (!value)
1787        return false;
1788
1789    // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
1790    // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
1791    ASSERT(!m_parsedCalculation);
1792
1793    CSSValueID id = value->id;
1794
1795    unsigned num = inShorthand() ? 1 : m_valueList->size();
1796
1797    if (id == CSSValueInherit) {
1798        if (num != 1)
1799            return false;
1800        addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important);
1801        return true;
1802    }
1803    else if (id == CSSValueInitial) {
1804        if (num != 1)
1805            return false;
1806        addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important);
1807        return true;
1808    }
1809
1810    if (isKeywordPropertyID(propId)) {
1811        if (!isValidKeywordPropertyAndValue(propId, id, m_context))
1812            return false;
1813        if (m_valueList->next() && !inShorthand())
1814            return false;
1815        addProperty(propId, cssValuePool().createIdentifierValue(id), important);
1816        return true;
1817    }
1818
1819#if ENABLE(CSS_DEVICE_ADAPTATION)
1820    if (inViewport())
1821        return parseViewportProperty(propId, important);
1822#endif
1823
1824    bool validPrimitive = false;
1825    RefPtr<CSSValue> parsedValue;
1826
1827    switch (propId) {
1828    case CSSPropertySize:                 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
1829        return parseSize(propId, important);
1830
1831    case CSSPropertyQuotes:               // [<string> <string>]+ | none | inherit
1832        if (id)
1833            validPrimitive = true;
1834        else
1835            return parseQuotes(propId, important);
1836        break;
1837    case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | isolate-override | plaintext | inherit
1838        if (id == CSSValueNormal
1839            || id == CSSValueEmbed
1840            || id == CSSValueBidiOverride
1841            || id == CSSValueWebkitIsolate
1842            || id == CSSValueWebkitIsolateOverride
1843            || id == CSSValueWebkitPlaintext)
1844            validPrimitive = true;
1845        break;
1846
1847    case CSSPropertyContent:              // [ <string> | <uri> | <counter> | attr(X) | open-quote |
1848        // close-quote | no-open-quote | no-close-quote ]+ | inherit
1849        return parseContent(propId, important);
1850
1851    case CSSPropertyWebkitAlt: // [ <string> | attr(X) ]
1852        return parseAlt(propId, important);
1853
1854    case CSSPropertyClip:                 // <shape> | auto | inherit
1855        if (id == CSSValueAuto)
1856            validPrimitive = true;
1857        else if (value->unit == CSSParserValue::Function)
1858            return parseClipShape(propId, important);
1859        break;
1860
1861    /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
1862     * correctly and allows optimization in WebCore::applyRule(..)
1863     */
1864    case CSSPropertyOverflow: {
1865        ShorthandScope scope(this, propId);
1866        if (num != 1 || !parseValue(CSSPropertyOverflowY, important))
1867            return false;
1868
1869        RefPtr<CSSValue> overflowXValue;
1870
1871        // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been
1872        // set using the shorthand, then for now overflow-x will default to auto, but once we implement
1873        // pagination controls, it should default to hidden. If the overflow-y value is anything but
1874        // paged-x or paged-y, then overflow-x and overflow-y should have the same value.
1875        if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
1876            overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
1877        else
1878            overflowXValue = m_parsedProperties.last().value();
1879        addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
1880        return true;
1881    }
1882
1883    case CSSPropertyTextAlign:
1884        // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
1885        // | start | end | inherit | -webkit-auto (converted to start)
1886        // NOTE: <string> is not supported.
1887        if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd)
1888            validPrimitive = true;
1889        break;
1890
1891    case CSSPropertyFontWeight:  { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
1892        if (m_valueList->size() != 1)
1893            return false;
1894        return parseFontWeight(important);
1895    }
1896    case CSSPropertyBorderSpacing: {
1897        if (num == 1) {
1898            ShorthandScope scope(this, CSSPropertyBorderSpacing);
1899            if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
1900                return false;
1901            CSSValue* value = m_parsedProperties.last().value();
1902            addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
1903            return true;
1904        }
1905        else if (num == 2) {
1906            ShorthandScope scope(this, CSSPropertyBorderSpacing);
1907            if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
1908                return false;
1909            return true;
1910        }
1911        return false;
1912    }
1913    case CSSPropertyWebkitBorderHorizontalSpacing:
1914    case CSSPropertyWebkitBorderVerticalSpacing:
1915        validPrimitive = validUnit(value, FLength | FNonNeg);
1916        break;
1917    case CSSPropertyOutlineColor:        // <color> | invert | inherit
1918        // Outline color has "invert" as additional keyword.
1919        // Also, we want to allow the special focus color even in strict parsing mode.
1920        if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
1921            validPrimitive = true;
1922            break;
1923        }
1924        FALLTHROUGH;
1925    case CSSPropertyBackgroundColor: // <color> | inherit
1926    case CSSPropertyBorderTopColor: // <color> | inherit
1927    case CSSPropertyBorderRightColor:
1928    case CSSPropertyBorderBottomColor:
1929    case CSSPropertyBorderLeftColor:
1930    case CSSPropertyWebkitBorderStartColor:
1931    case CSSPropertyWebkitBorderEndColor:
1932    case CSSPropertyWebkitBorderBeforeColor:
1933    case CSSPropertyWebkitBorderAfterColor:
1934    case CSSPropertyColor: // <color> | inherit
1935    case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors
1936    case CSSPropertyTextUnderlineColor:
1937    case CSSPropertyTextOverlineColor:
1938    case CSSPropertyWebkitColumnRuleColor:
1939    case CSSPropertyWebkitTextDecorationColor:
1940    case CSSPropertyWebkitTextEmphasisColor:
1941    case CSSPropertyWebkitTextFillColor:
1942    case CSSPropertyWebkitTextStrokeColor:
1943        if (id == CSSValueWebkitText)
1944            validPrimitive = true; // Always allow this, even when strict parsing is on,
1945                                    // since we use this in our UA sheets.
1946        else if (id == CSSValueCurrentcolor)
1947            validPrimitive = true;
1948        else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu ||
1949             (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
1950            validPrimitive = true;
1951        } else {
1952            parsedValue = parseColor();
1953            if (parsedValue)
1954                m_valueList->next();
1955        }
1956        break;
1957
1958    case CSSPropertyCursor: {
1959        // Grammar defined by CSS3 UI and modified by CSS4 images:
1960        // [ [<image> [<x> <y>]?,]*
1961        // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
1962        // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
1963        // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
1964        // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
1965        // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
1966        RefPtr<CSSValueList> list;
1967        while (value) {
1968            RefPtr<CSSValue> image = 0;
1969            if (value->unit == CSSPrimitiveValue::CSS_URI) {
1970                String uri = value->string;
1971                if (!uri.isNull())
1972                    image = CSSImageValue::create(completeURL(uri));
1973#if ENABLE(CSS_IMAGE_SET) && ENABLE(MOUSE_CURSOR_SCALE)
1974            } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
1975                image = parseImageSet();
1976                if (!image)
1977                    break;
1978#endif
1979            } else
1980                break;
1981
1982            Vector<int> coords;
1983            value = m_valueList->next();
1984            while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
1985                coords.append(int(value->fValue));
1986                value = m_valueList->next();
1987            }
1988            bool hasHotSpot = false;
1989            IntPoint hotSpot(-1, -1);
1990            int nrcoords = coords.size();
1991            if (nrcoords > 0 && nrcoords != 2)
1992                return false;
1993            if (nrcoords == 2) {
1994                hasHotSpot = true;
1995                hotSpot = IntPoint(coords[0], coords[1]);
1996            }
1997
1998            if (!list)
1999                list = CSSValueList::createCommaSeparated();
2000
2001            if (image)
2002                list->append(CSSCursorImageValue::create(image.releaseNonNull(), hasHotSpot, hotSpot));
2003
2004            if ((inStrictMode() && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ',')))
2005                return false;
2006            value = m_valueList->next(); // comma
2007        }
2008        if (list) {
2009            if (!value) { // no value after url list (MSIE 5 compatibility)
2010                if (list->length() != 1)
2011                    return false;
2012            } else if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
2013                list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
2014            else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
2015                list->append(cssValuePool().createIdentifierValue(value->id));
2016            m_valueList->next();
2017            parsedValue = list.release();
2018            break;
2019        } else if (value) {
2020            id = value->id;
2021            if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
2022                id = CSSValuePointer;
2023                validPrimitive = true;
2024            } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
2025                validPrimitive = true;
2026        } else {
2027            ASSERT_NOT_REACHED();
2028            return false;
2029        }
2030        break;
2031    }
2032
2033#if ENABLE(CURSOR_VISIBILITY)
2034    case CSSPropertyWebkitCursorVisibility:
2035        if (id == CSSValueAuto || id == CSSValueAutoHide)
2036            validPrimitive = true;
2037        break;
2038#endif
2039
2040    case CSSPropertyBackgroundAttachment:
2041    case CSSPropertyBackgroundBlendMode:
2042    case CSSPropertyBackgroundClip:
2043    case CSSPropertyWebkitBackgroundClip:
2044    case CSSPropertyWebkitBackgroundComposite:
2045    case CSSPropertyBackgroundImage:
2046    case CSSPropertyBackgroundOrigin:
2047    case CSSPropertyWebkitBackgroundOrigin:
2048    case CSSPropertyBackgroundPosition:
2049    case CSSPropertyBackgroundPositionX:
2050    case CSSPropertyBackgroundPositionY:
2051    case CSSPropertyBackgroundSize:
2052    case CSSPropertyWebkitBackgroundSize:
2053    case CSSPropertyBackgroundRepeat:
2054    case CSSPropertyBackgroundRepeatX:
2055    case CSSPropertyBackgroundRepeatY:
2056    case CSSPropertyWebkitMaskClip:
2057    case CSSPropertyWebkitMaskComposite:
2058    case CSSPropertyWebkitMaskImage:
2059    case CSSPropertyWebkitMaskOrigin:
2060    case CSSPropertyWebkitMaskPosition:
2061    case CSSPropertyWebkitMaskPositionX:
2062    case CSSPropertyWebkitMaskPositionY:
2063    case CSSPropertyWebkitMaskSize:
2064    case CSSPropertyWebkitMaskSourceType:
2065    case CSSPropertyWebkitMaskRepeat:
2066    case CSSPropertyWebkitMaskRepeatX:
2067    case CSSPropertyWebkitMaskRepeatY:
2068    {
2069        RefPtr<CSSValue> val1;
2070        RefPtr<CSSValue> val2;
2071        CSSPropertyID propId1, propId2;
2072        bool result = false;
2073        if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
2074            std::unique_ptr<ShorthandScope> shorthandScope;
2075            if (propId == CSSPropertyBackgroundPosition ||
2076                propId == CSSPropertyBackgroundRepeat ||
2077                propId == CSSPropertyWebkitMaskPosition ||
2078                propId == CSSPropertyWebkitMaskRepeat) {
2079                shorthandScope = std::make_unique<ShorthandScope>(this, propId);
2080            }
2081            addProperty(propId1, val1.release(), important);
2082            if (val2)
2083                addProperty(propId2, val2.release(), important);
2084            result = true;
2085        }
2086        m_implicitShorthand = false;
2087        return result;
2088    }
2089    case CSSPropertyListStyleImage:     // <uri> | none | inherit
2090    case CSSPropertyBorderImageSource:
2091    case CSSPropertyWebkitMaskBoxImageSource:
2092        if (id == CSSValueNone) {
2093            parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
2094            m_valueList->next();
2095        } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
2096            parsedValue = CSSImageValue::create(completeURL(value->string));
2097            m_valueList->next();
2098        } else if (isGeneratedImageValue(value)) {
2099            if (parseGeneratedImage(m_valueList.get(), parsedValue))
2100                m_valueList->next();
2101            else
2102                return false;
2103        }
2104#if ENABLE(CSS_IMAGE_SET)
2105        else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
2106            parsedValue = parseImageSet();
2107            if (!parsedValue)
2108                return false;
2109            m_valueList->next();
2110        }
2111#endif
2112        break;
2113
2114    case CSSPropertyWebkitTextStrokeWidth:
2115    case CSSPropertyOutlineWidth:        // <border-width> | inherit
2116    case CSSPropertyBorderTopWidth:     //// <border-width> | inherit
2117    case CSSPropertyBorderRightWidth:   //   Which is defined as
2118    case CSSPropertyBorderBottomWidth:  //   thin | medium | thick | <length>
2119    case CSSPropertyBorderLeftWidth:
2120    case CSSPropertyWebkitBorderStartWidth:
2121    case CSSPropertyWebkitBorderEndWidth:
2122    case CSSPropertyWebkitBorderBeforeWidth:
2123    case CSSPropertyWebkitBorderAfterWidth:
2124    case CSSPropertyWebkitColumnRuleWidth:
2125        if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
2126            validPrimitive = true;
2127        else
2128            validPrimitive = validUnit(value, FLength | FNonNeg);
2129        break;
2130
2131    case CSSPropertyLetterSpacing:       // normal | <length> | inherit
2132        if (id == CSSValueNormal)
2133            validPrimitive = true;
2134        else
2135            validPrimitive = validUnit(value, FLength);
2136        break;
2137
2138    case CSSPropertyWordSpacing:         // normal | <length> | <percentage> | inherit
2139        if (id == CSSValueNormal)
2140            validPrimitive = true;
2141        else
2142            validPrimitive = validUnit(value, FLength | FPercent);
2143        break;
2144
2145    case CSSPropertyTextIndent:
2146        parsedValue = parseTextIndent();
2147        break;
2148
2149    case CSSPropertyPaddingTop:          //// <padding-width> | inherit
2150    case CSSPropertyPaddingRight:        //   Which is defined as
2151    case CSSPropertyPaddingBottom:       //   <length> | <percentage>
2152    case CSSPropertyPaddingLeft:         ////
2153    case CSSPropertyWebkitPaddingStart:
2154    case CSSPropertyWebkitPaddingEnd:
2155    case CSSPropertyWebkitPaddingBefore:
2156    case CSSPropertyWebkitPaddingAfter:
2157        validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
2158        break;
2159
2160    case CSSPropertyMaxWidth:
2161    case CSSPropertyWebkitMaxLogicalWidth:
2162        validPrimitive = (id == CSSValueNone || validWidth(value));
2163        break;
2164
2165    case CSSPropertyMinWidth:
2166    case CSSPropertyWebkitMinLogicalWidth:
2167        validPrimitive = validWidth(value);
2168        break;
2169
2170    case CSSPropertyWidth:
2171    case CSSPropertyWebkitLogicalWidth:
2172        validPrimitive = (id == CSSValueAuto || validWidth(value));
2173        break;
2174
2175    case CSSPropertyMaxHeight:
2176    case CSSPropertyWebkitMaxLogicalHeight:
2177        validPrimitive = (id == CSSValueNone || validHeight(value));
2178        break;
2179
2180    case CSSPropertyMinHeight:
2181    case CSSPropertyWebkitMinLogicalHeight:
2182        validPrimitive = validHeight(value);
2183        break;
2184
2185    case CSSPropertyHeight:
2186    case CSSPropertyWebkitLogicalHeight:
2187        validPrimitive = (id == CSSValueAuto || validHeight(value));
2188        break;
2189
2190    case CSSPropertyFontSize:
2191        return parseFontSize(important);
2192
2193    case CSSPropertyFontVariant:         // normal | small-caps | inherit
2194        return parseFontVariant(important);
2195
2196    case CSSPropertyVerticalAlign:
2197        // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
2198        // <percentage> | <length> | inherit
2199
2200        if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
2201            validPrimitive = true;
2202        else
2203            validPrimitive = (!id && validUnit(value, FLength | FPercent));
2204        break;
2205
2206    case CSSPropertyBottom:               // <length> | <percentage> | auto | inherit
2207    case CSSPropertyLeft:                 // <length> | <percentage> | auto | inherit
2208    case CSSPropertyRight:                // <length> | <percentage> | auto | inherit
2209    case CSSPropertyTop:                  // <length> | <percentage> | auto | inherit
2210    case CSSPropertyMarginTop:           //// <margin-width> | inherit
2211    case CSSPropertyMarginRight:         //   Which is defined as
2212    case CSSPropertyMarginBottom:        //   <length> | <percentage> | auto | inherit
2213    case CSSPropertyMarginLeft:          ////
2214    case CSSPropertyWebkitMarginStart:
2215    case CSSPropertyWebkitMarginEnd:
2216    case CSSPropertyWebkitMarginBefore:
2217    case CSSPropertyWebkitMarginAfter:
2218        if (id == CSSValueAuto)
2219            validPrimitive = true;
2220        else
2221            validPrimitive = (!id && validUnit(value, FLength | FPercent));
2222        break;
2223
2224    case CSSPropertyZIndex:              // auto | <integer> | inherit
2225        if (id == CSSValueAuto)
2226            validPrimitive = true;
2227        else
2228            validPrimitive = (!id && validUnit(value, FInteger, CSSQuirksMode));
2229        break;
2230
2231    case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
2232    case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
2233        if (id == CSSValueAuto)
2234            validPrimitive = true;
2235        else
2236            validPrimitive = (!id && validUnit(value, FPositiveInteger, CSSQuirksMode));
2237        break;
2238
2239    case CSSPropertyLineHeight:
2240        return parseLineHeight(important);
2241    case CSSPropertyCounterIncrement:    // [ <identifier> <integer>? ]+ | none | inherit
2242        if (id != CSSValueNone)
2243            return parseCounter(propId, 1, important);
2244        validPrimitive = true;
2245        break;
2246    case CSSPropertyCounterReset:        // [ <identifier> <integer>? ]+ | none | inherit
2247        if (id != CSSValueNone)
2248            return parseCounter(propId, 0, important);
2249        validPrimitive = true;
2250        break;
2251    case CSSPropertyFontFamily:
2252        // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
2253    {
2254        parsedValue = parseFontFamily();
2255        break;
2256    }
2257
2258    case CSSPropertyWebkitTextDecoration:
2259        // [ <text-decoration-line> || <text-decoration-style> || <text-decoration-color> ] | inherit
2260        return parseShorthand(CSSPropertyWebkitTextDecoration, webkitTextDecorationShorthand(), important);
2261
2262    case CSSPropertyTextDecoration:
2263    case CSSPropertyWebkitTextDecorationsInEffect:
2264    case CSSPropertyWebkitTextDecorationLine:
2265        // none | [ underline || overline || line-through || blink ] | inherit
2266        return parseTextDecoration(propId, important);
2267
2268    case CSSPropertyWebkitTextDecorationStyle:
2269        // solid | double | dotted | dashed | wavy
2270        if (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDotted || id == CSSValueDashed || id == CSSValueWavy)
2271            validPrimitive = true;
2272        break;
2273
2274    case CSSPropertyWebkitTextDecorationSkip:
2275        // none | [ objects || spaces || ink || edges || box-decoration ]
2276        return parseTextDecorationSkip(important);
2277
2278    case CSSPropertyWebkitTextUnderlinePosition:
2279        // auto | alphabetic | under
2280        return parseTextUnderlinePosition(important);
2281
2282    case CSSPropertyZoom:          // normal | reset | document | <number> | <percentage> | inherit
2283        if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
2284            validPrimitive = true;
2285        else
2286            validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode));
2287        break;
2288
2289    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.
2290        return parseFontFaceSrc();
2291
2292    case CSSPropertyUnicodeRange:
2293        return parseFontFaceUnicodeRange();
2294
2295    /* CSS3 properties */
2296
2297    case CSSPropertyBorderImage: {
2298        RefPtr<CSSValue> result;
2299        return parseBorderImage(propId, result, important);
2300    }
2301    case CSSPropertyWebkitBorderImage:
2302    case CSSPropertyWebkitMaskBoxImage: {
2303        RefPtr<CSSValue> result;
2304        if (parseBorderImage(propId, result)) {
2305            addProperty(propId, result, important);
2306            return true;
2307        }
2308        break;
2309    }
2310    case CSSPropertyBorderImageOutset:
2311    case CSSPropertyWebkitMaskBoxImageOutset: {
2312        RefPtr<CSSPrimitiveValue> result;
2313        if (parseBorderImageOutset(result)) {
2314            addProperty(propId, result, important);
2315            return true;
2316        }
2317        break;
2318    }
2319    case CSSPropertyBorderImageRepeat:
2320    case CSSPropertyWebkitMaskBoxImageRepeat: {
2321        RefPtr<CSSValue> result;
2322        if (parseBorderImageRepeat(result)) {
2323            addProperty(propId, result, important);
2324            return true;
2325        }
2326        break;
2327    }
2328    case CSSPropertyBorderImageSlice:
2329    case CSSPropertyWebkitMaskBoxImageSlice: {
2330        RefPtr<CSSBorderImageSliceValue> result;
2331        if (parseBorderImageSlice(propId, result)) {
2332            addProperty(propId, result, important);
2333            return true;
2334        }
2335        break;
2336    }
2337    case CSSPropertyBorderImageWidth:
2338    case CSSPropertyWebkitMaskBoxImageWidth: {
2339        RefPtr<CSSPrimitiveValue> result;
2340        if (parseBorderImageWidth(result)) {
2341            addProperty(propId, result, important);
2342            return true;
2343        }
2344        break;
2345    }
2346    case CSSPropertyBorderTopRightRadius:
2347    case CSSPropertyBorderTopLeftRadius:
2348    case CSSPropertyBorderBottomLeftRadius:
2349    case CSSPropertyBorderBottomRightRadius: {
2350        if (num != 1 && num != 2)
2351            return false;
2352        validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2353        if (!validPrimitive)
2354            return false;
2355        RefPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
2356        RefPtr<CSSPrimitiveValue> parsedValue2;
2357        if (num == 2) {
2358            value = m_valueList->next();
2359            validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2360            if (!validPrimitive)
2361                return false;
2362            parsedValue2 = createPrimitiveNumericValue(value);
2363        } else
2364            parsedValue2 = parsedValue1;
2365
2366        addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important);
2367        return true;
2368    }
2369    case CSSPropertyTabSize:
2370        validPrimitive = validUnit(value, FInteger | FNonNeg);
2371        break;
2372    case CSSPropertyWebkitAspectRatio:
2373        return parseAspectRatio(important);
2374    case CSSPropertyBorderRadius:
2375    case CSSPropertyWebkitBorderRadius:
2376        return parseBorderRadius(propId, important);
2377    case CSSPropertyOutlineOffset:
2378        validPrimitive = validUnit(value, FLength);
2379        break;
2380    case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
2381    case CSSPropertyBoxShadow:
2382    case CSSPropertyWebkitBoxShadow:
2383        if (id == CSSValueNone)
2384            validPrimitive = true;
2385        else {
2386            RefPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
2387            if (shadowValueList) {
2388                addProperty(propId, shadowValueList.release(), important);
2389                m_valueList->next();
2390                return true;
2391            }
2392            return false;
2393        }
2394        break;
2395    case CSSPropertyWebkitBoxReflect:
2396        if (id == CSSValueNone)
2397            validPrimitive = true;
2398        else
2399            return parseReflect(propId, important);
2400        break;
2401    case CSSPropertyOpacity:
2402        validPrimitive = validUnit(value, FNumber);
2403        break;
2404    case CSSPropertyWebkitBoxFlex:
2405        validPrimitive = validUnit(value, FNumber);
2406        break;
2407    case CSSPropertyWebkitBoxFlexGroup:
2408        validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode);
2409        break;
2410    case CSSPropertyWebkitBoxOrdinalGroup:
2411        validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode) && value->fValue;
2412        break;
2413#if ENABLE(CSS_FILTERS)
2414    case CSSPropertyWebkitFilter:
2415        if (id == CSSValueNone)
2416            validPrimitive = true;
2417        else {
2418            RefPtr<CSSValue> currValue;
2419            if (!parseFilter(m_valueList.get(), currValue))
2420                return false;
2421            addProperty(propId, currValue, important);
2422            return true;
2423        }
2424        break;
2425#endif
2426#if ENABLE(CSS_COMPOSITING)
2427    case CSSPropertyMixBlendMode:
2428        if (cssCompositingEnabled())
2429            validPrimitive = true;
2430        break;
2431    case CSSPropertyIsolation:
2432        if (cssCompositingEnabled())
2433            validPrimitive = true;
2434        break;
2435#endif
2436    case CSSPropertyWebkitFlex: {
2437        ShorthandScope scope(this, propId);
2438        if (id == CSSValueNone) {
2439            addProperty(CSSPropertyWebkitFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
2440            addProperty(CSSPropertyWebkitFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
2441            addProperty(CSSPropertyWebkitFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
2442            return true;
2443        }
2444        return parseFlex(m_valueList.get(), important);
2445    }
2446    case CSSPropertyWebkitFlexBasis:
2447        // FIXME: Support intrinsic dimensions too.
2448        if (id == CSSValueAuto)
2449            validPrimitive = true;
2450        else
2451            validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
2452        break;
2453    case CSSPropertyWebkitFlexGrow:
2454    case CSSPropertyWebkitFlexShrink:
2455        validPrimitive = validUnit(value, FNumber | FNonNeg);
2456        break;
2457    case CSSPropertyWebkitOrder:
2458        if (validUnit(value, FInteger, CSSStrictMode)) {
2459            // 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.
2460            parsedValue = cssValuePool().createValue(std::max<double>(std::numeric_limits<int>::min() + 2, value->fValue), static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
2461            m_valueList->next();
2462        }
2463        break;
2464    case CSSPropertyWebkitMarquee:
2465        return parseShorthand(propId, webkitMarqueeShorthand(), important);
2466    case CSSPropertyWebkitMarqueeIncrement:
2467        if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
2468            validPrimitive = true;
2469        else
2470            validPrimitive = validUnit(value, FLength | FPercent);
2471        break;
2472    case CSSPropertyWebkitMarqueeRepetition:
2473        if (id == CSSValueInfinite)
2474            validPrimitive = true;
2475        else
2476            validPrimitive = validUnit(value, FInteger | FNonNeg);
2477        break;
2478    case CSSPropertyWebkitMarqueeSpeed:
2479        if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
2480            validPrimitive = true;
2481        else
2482            validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
2483        break;
2484#if ENABLE(CSS_REGIONS)
2485    case CSSPropertyWebkitFlowInto:
2486        if (!cssRegionsEnabled())
2487            return false;
2488        return parseFlowThread(propId, important);
2489    case CSSPropertyWebkitFlowFrom:
2490        if (!cssRegionsEnabled())
2491            return false;
2492        return parseRegionThread(propId, important);
2493#endif
2494    case CSSPropertyWebkitTransform:
2495        if (id == CSSValueNone)
2496            validPrimitive = true;
2497        else {
2498            RefPtr<CSSValue> transformValue = parseTransform();
2499            if (transformValue) {
2500                addProperty(propId, transformValue.release(), important);
2501                return true;
2502            }
2503            return false;
2504        }
2505        break;
2506    case CSSPropertyWebkitTransformOrigin:
2507    case CSSPropertyWebkitTransformOriginX:
2508    case CSSPropertyWebkitTransformOriginY:
2509    case CSSPropertyWebkitTransformOriginZ: {
2510        RefPtr<CSSValue> val1;
2511        RefPtr<CSSValue> val2;
2512        RefPtr<CSSValue> val3;
2513        CSSPropertyID propId1, propId2, propId3;
2514        if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
2515            addProperty(propId1, val1.release(), important);
2516            if (val2)
2517                addProperty(propId2, val2.release(), important);
2518            if (val3)
2519                addProperty(propId3, val3.release(), important);
2520            return true;
2521        }
2522        return false;
2523    }
2524    case CSSPropertyWebkitPerspective:
2525        if (id == CSSValueNone)
2526            validPrimitive = true;
2527        else {
2528            // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
2529            if (validUnit(value, FNumber | FLength | FNonNeg)) {
2530                RefPtr<CSSValue> val = createPrimitiveNumericValue(value);
2531                if (val) {
2532                    addProperty(propId, val.release(), important);
2533                    return true;
2534                }
2535                return false;
2536            }
2537        }
2538        break;
2539    case CSSPropertyWebkitPerspectiveOrigin:
2540    case CSSPropertyWebkitPerspectiveOriginX:
2541    case CSSPropertyWebkitPerspectiveOriginY: {
2542        RefPtr<CSSValue> val1;
2543        RefPtr<CSSValue> val2;
2544        CSSPropertyID propId1, propId2;
2545        if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
2546            addProperty(propId1, val1.release(), important);
2547            if (val2)
2548                addProperty(propId2, val2.release(), important);
2549            return true;
2550        }
2551        return false;
2552    }
2553    case CSSPropertyWebkitAnimationDelay:
2554    case CSSPropertyWebkitAnimationDirection:
2555    case CSSPropertyWebkitAnimationDuration:
2556    case CSSPropertyWebkitAnimationFillMode:
2557    case CSSPropertyWebkitAnimationName:
2558    case CSSPropertyWebkitAnimationPlayState:
2559    case CSSPropertyWebkitAnimationIterationCount:
2560    case CSSPropertyWebkitAnimationTimingFunction:
2561    case CSSPropertyTransitionDelay:
2562    case CSSPropertyTransitionDuration:
2563    case CSSPropertyTransitionTimingFunction:
2564    case CSSPropertyTransitionProperty:
2565    case CSSPropertyWebkitTransitionDelay:
2566    case CSSPropertyWebkitTransitionDuration:
2567    case CSSPropertyWebkitTransitionTimingFunction:
2568    case CSSPropertyWebkitTransitionProperty: {
2569        RefPtr<CSSValue> val;
2570        AnimationParseContext context;
2571        if (parseAnimationProperty(propId, val, context)) {
2572            addPropertyWithPrefixingVariant(propId, val.release(), important);
2573            return true;
2574        }
2575        return false;
2576    }
2577    case CSSPropertyWebkitJustifySelf:
2578        return parseJustifySelf(propId, important);
2579#if ENABLE(CSS_GRID_LAYOUT)
2580    case CSSPropertyWebkitGridAutoColumns:
2581    case CSSPropertyWebkitGridAutoRows:
2582        parsedValue = parseGridTrackSize(*m_valueList);
2583        break;
2584
2585    case CSSPropertyWebkitGridTemplateColumns:
2586    case CSSPropertyWebkitGridTemplateRows:
2587        parsedValue = parseGridTrackList();
2588        break;
2589
2590    case CSSPropertyWebkitGridColumnStart:
2591    case CSSPropertyWebkitGridColumnEnd:
2592    case CSSPropertyWebkitGridRowStart:
2593    case CSSPropertyWebkitGridRowEnd:
2594        parsedValue = parseGridPosition();
2595        break;
2596
2597    case CSSPropertyWebkitGridColumn:
2598    case CSSPropertyWebkitGridRow: {
2599        return parseGridItemPositionShorthand(propId, important);
2600    }
2601
2602    case CSSPropertyWebkitGridTemplate:
2603        return parseGridTemplateShorthand(important);
2604
2605    case CSSPropertyWebkitGrid:
2606        return parseGridShorthand(important);
2607
2608    case CSSPropertyWebkitGridArea:
2609        return parseGridAreaShorthand(important);
2610
2611    case CSSPropertyWebkitGridTemplateAreas:
2612        parsedValue = parseGridTemplateAreas();
2613        break;
2614    case CSSPropertyWebkitGridAutoFlow:
2615        parsedValue = parseGridAutoFlow(*m_valueList);
2616        break;
2617#endif /* ENABLE(CSS_GRID_LAYOUT) */
2618    case CSSPropertyWebkitMarginCollapse: {
2619        if (num == 1) {
2620            ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2621            if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important))
2622                return false;
2623            CSSValue* value = m_parsedProperties.last().value();
2624            addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
2625            return true;
2626        }
2627        else if (num == 2) {
2628            ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2629            if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important) || !parseValue(webkitMarginCollapseShorthand().properties()[1], important))
2630                return false;
2631            return true;
2632        }
2633        return false;
2634    }
2635    case CSSPropertyTextLineThroughWidth:
2636    case CSSPropertyTextOverlineWidth:
2637    case CSSPropertyTextUnderlineWidth:
2638        if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
2639            id == CSSValueMedium || id == CSSValueThick)
2640            validPrimitive = true;
2641        else
2642            validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent);
2643        break;
2644    case CSSPropertyWebkitColumnCount:
2645        if (id == CSSValueAuto)
2646            validPrimitive = true;
2647        else
2648            validPrimitive = !id && validUnit(value, FPositiveInteger, CSSQuirksMode);
2649        break;
2650    case CSSPropertyWebkitColumnGap:         // normal | <length>
2651        if (id == CSSValueNormal)
2652            validPrimitive = true;
2653        else
2654            validPrimitive = validUnit(value, FLength | FNonNeg);
2655        break;
2656    case CSSPropertyWebkitColumnAxis:
2657        if (id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
2658            validPrimitive = true;
2659        break;
2660    case CSSPropertyWebkitColumnProgression:
2661        if (id == CSSValueNormal || id == CSSValueReverse)
2662            validPrimitive = true;
2663        break;
2664    case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property)
2665        if (id == CSSValueAll || id == CSSValueNone)
2666            validPrimitive = true;
2667        else
2668            validPrimitive = validUnit(value, FNumber | FNonNeg) && value->fValue == 1;
2669        break;
2670    case CSSPropertyWebkitColumnWidth:         // auto | <length>
2671        if (id == CSSValueAuto)
2672            validPrimitive = true;
2673        else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property.
2674            validPrimitive = validUnit(value, FLength | FNonNeg, CSSStrictMode) && value->fValue;
2675        break;
2676    // End of CSS3 properties
2677
2678    // Apple specific properties.  These will never be standardized and are purely to
2679    // support custom WebKit-based Apple applications.
2680    case CSSPropertyWebkitLineClamp:
2681        // When specifying number of lines, don't allow 0 as a valid value
2682        // When specifying either type of unit, require non-negative integers
2683        validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, CSSQuirksMode));
2684        break;
2685#if ENABLE(IOS_TEXT_AUTOSIZING)
2686    case CSSPropertyWebkitTextSizeAdjust:
2687        if (id == CSSValueAuto || id == CSSValueNone)
2688            validPrimitive = true;
2689        else {
2690            // FIXME: Handle multilength case where we allow relative units.
2691            validPrimitive = (!id && validUnit(value, FPercent | FNonNeg, CSSStrictMode));
2692        }
2693        break;
2694#endif
2695
2696    case CSSPropertyWebkitFontSizeDelta:           // <length>
2697        validPrimitive = validUnit(value, FLength);
2698        break;
2699
2700    case CSSPropertyWebkitHyphenateCharacter:
2701        if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2702            validPrimitive = true;
2703        break;
2704
2705    case CSSPropertyWebkitHyphenateLimitBefore:
2706    case CSSPropertyWebkitHyphenateLimitAfter:
2707        if (id == CSSValueAuto || validUnit(value, FInteger | FNonNeg, CSSStrictMode))
2708            validPrimitive = true;
2709        break;
2710
2711    case CSSPropertyWebkitHyphenateLimitLines:
2712        if (id == CSSValueNoLimit || validUnit(value, FInteger | FNonNeg, CSSStrictMode))
2713            validPrimitive = true;
2714        break;
2715
2716    case CSSPropertyWebkitLineGrid:
2717        if (id == CSSValueNone)
2718            validPrimitive = true;
2719        else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
2720            String lineGridValue = String(value->string);
2721            if (!lineGridValue.isEmpty()) {
2722                addProperty(propId, cssValuePool().createValue(lineGridValue, CSSPrimitiveValue::CSS_STRING), important);
2723                return true;
2724            }
2725        }
2726        break;
2727    case CSSPropertyWebkitLocale:
2728        if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2729            validPrimitive = true;
2730        break;
2731
2732#if ENABLE(DASHBOARD_SUPPORT)
2733    case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region>
2734        if (value->unit == CSSParserValue::Function || id == CSSValueNone)
2735            return parseDashboardRegions(propId, important);
2736        break;
2737#endif
2738
2739#if PLATFORM(IOS)
2740    // FIXME: CSSPropertyWebkitCompositionFillColor shouldn't be iOS-specific. Once we fix up its usage in
2741    // InlineTextBox::paintCompositionBackground() we should move it outside the PLATFORM(IOS)-guard.
2742    // See <https://bugs.webkit.org/show_bug.cgi?id=126296>.
2743    case CSSPropertyWebkitCompositionFillColor:
2744        if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu
2745            || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
2746            validPrimitive = true;
2747        } else {
2748            parsedValue = parseColor();
2749            if (parsedValue)
2750                m_valueList->next();
2751        }
2752        break;
2753    case CSSPropertyWebkitTouchCallout:
2754        if (id == CSSValueDefault || id == CSSValueNone)
2755            validPrimitive = true;
2756        break;
2757#endif
2758#if ENABLE(TOUCH_EVENTS)
2759    case CSSPropertyWebkitTapHighlightColor:
2760        if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu
2761            || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
2762            validPrimitive = true;
2763        } else {
2764            parsedValue = parseColor();
2765            if (parsedValue)
2766                m_valueList->next();
2767        }
2768        break;
2769#endif
2770    // End Apple-specific properties
2771
2772        /* shorthand properties */
2773    case CSSPropertyBackground: {
2774        // Position must come before color in this array because a plain old "0" is a legal color
2775        // in quirks mode but it's usually the X coordinate of a position.
2776        const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
2777                                   CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
2778                                   CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
2779        return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
2780    }
2781    case CSSPropertyWebkitMask: {
2782        const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskSourceType, CSSPropertyWebkitMaskRepeat,
2783            CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize };
2784        return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
2785    }
2786    case CSSPropertyBorder:
2787        // [ 'border-width' || 'border-style' || <color> ] | inherit
2788    {
2789        if (parseShorthand(propId, borderAbridgedShorthand(), important)) {
2790            // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as
2791            // though a value of none was specified for the image.
2792            addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
2793            return true;
2794        }
2795        return false;
2796    }
2797    case CSSPropertyBorderTop:
2798        // [ 'border-top-width' || 'border-style' || <color> ] | inherit
2799        return parseShorthand(propId, borderTopShorthand(), important);
2800    case CSSPropertyBorderRight:
2801        // [ 'border-right-width' || 'border-style' || <color> ] | inherit
2802        return parseShorthand(propId, borderRightShorthand(), important);
2803    case CSSPropertyBorderBottom:
2804        // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
2805        return parseShorthand(propId, borderBottomShorthand(), important);
2806    case CSSPropertyBorderLeft:
2807        // [ 'border-left-width' || 'border-style' || <color> ] | inherit
2808        return parseShorthand(propId, borderLeftShorthand(), important);
2809    case CSSPropertyWebkitBorderStart:
2810        return parseShorthand(propId, webkitBorderStartShorthand(), important);
2811    case CSSPropertyWebkitBorderEnd:
2812        return parseShorthand(propId, webkitBorderEndShorthand(), important);
2813    case CSSPropertyWebkitBorderBefore:
2814        return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
2815    case CSSPropertyWebkitBorderAfter:
2816        return parseShorthand(propId, webkitBorderAfterShorthand(), important);
2817    case CSSPropertyOutline:
2818        // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
2819        return parseShorthand(propId, outlineShorthand(), important);
2820    case CSSPropertyBorderColor:
2821        // <color>{1,4} | inherit
2822        return parse4Values(propId, borderColorShorthand().properties(), important);
2823    case CSSPropertyBorderWidth:
2824        // <border-width>{1,4} | inherit
2825        return parse4Values(propId, borderWidthShorthand().properties(), important);
2826    case CSSPropertyBorderStyle:
2827        // <border-style>{1,4} | inherit
2828        return parse4Values(propId, borderStyleShorthand().properties(), important);
2829    case CSSPropertyMargin:
2830        // <margin-width>{1,4} | inherit
2831        return parse4Values(propId, marginShorthand().properties(), important);
2832    case CSSPropertyPadding:
2833        // <padding-width>{1,4} | inherit
2834        return parse4Values(propId, paddingShorthand().properties(), important);
2835    case CSSPropertyWebkitFlexFlow:
2836        return parseShorthand(propId, webkitFlexFlowShorthand(), important);
2837    case CSSPropertyFont:
2838        // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
2839        // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
2840        if (id >= CSSValueCaption && id <= CSSValueStatusBar)
2841            validPrimitive = true;
2842        else
2843            return parseFont(important);
2844        break;
2845    case CSSPropertyListStyle:
2846        return parseShorthand(propId, listStyleShorthand(), important);
2847    case CSSPropertyWebkitColumns:
2848        return parseShorthand(propId, webkitColumnsShorthand(), important);
2849    case CSSPropertyWebkitColumnRule:
2850        return parseShorthand(propId, webkitColumnRuleShorthand(), important);
2851    case CSSPropertyWebkitTextStroke:
2852        return parseShorthand(propId, webkitTextStrokeShorthand(), important);
2853    case CSSPropertyWebkitAnimation:
2854        return parseAnimationShorthand(important);
2855    case CSSPropertyTransition:
2856    case CSSPropertyWebkitTransition:
2857        return parseTransitionShorthand(propId, important);
2858    case CSSPropertyInvalid:
2859        return false;
2860    case CSSPropertyPage:
2861        return parsePage(propId, important);
2862    case CSSPropertyFontStretch:
2863    case CSSPropertyTextLineThrough:
2864    case CSSPropertyTextOverline:
2865    case CSSPropertyTextUnderline:
2866        return false;
2867    // CSS Text Layout Module Level 3: Vertical writing support
2868    case CSSPropertyWebkitTextEmphasis:
2869        return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
2870
2871    case CSSPropertyWebkitTextEmphasisStyle:
2872        return parseTextEmphasisStyle(important);
2873
2874    case CSSPropertyWebkitTextEmphasisPosition:
2875        return parseTextEmphasisPosition(important);
2876
2877    case CSSPropertyWebkitTextOrientation:
2878        // FIXME: For now just support sideways, sideways-right, upright and vertical-right.
2879        if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSValueVerticalRight || id == CSSValueUpright)
2880            validPrimitive = true;
2881        break;
2882
2883    case CSSPropertyWebkitLineBoxContain:
2884        if (id == CSSValueNone)
2885            validPrimitive = true;
2886        else
2887            return parseLineBoxContain(important);
2888        break;
2889    case CSSPropertyWebkitFontFeatureSettings:
2890        if (id == CSSValueNormal)
2891            validPrimitive = true;
2892        else
2893            return parseFontFeatureSettings(important);
2894        break;
2895
2896    case CSSPropertyWebkitFontVariantLigatures:
2897        if (id == CSSValueNormal)
2898            validPrimitive = true;
2899        else
2900            return parseFontVariantLigatures(important);
2901        break;
2902    case CSSPropertyWebkitClipPath:
2903        parsedValue = parseClipPath();
2904        break;
2905#if ENABLE(CSS_SHAPES)
2906    case CSSPropertyWebkitShapeOutside:
2907        parsedValue = parseShapeProperty(propId);
2908        break;
2909    case CSSPropertyWebkitShapeMargin:
2910        validPrimitive = (RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled() && !id && validUnit(value, FLength | FPercent | FNonNeg));
2911        break;
2912    case CSSPropertyWebkitShapeImageThreshold:
2913        validPrimitive = (RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled() && !id && validUnit(value, FNumber));
2914        break;
2915#endif
2916#if ENABLE(CSS_IMAGE_ORIENTATION)
2917    case CSSPropertyImageOrientation:
2918        validPrimitive = !id && validUnit(value, FAngle);
2919        break;
2920#endif
2921#if ENABLE(CSS_IMAGE_RESOLUTION)
2922    case CSSPropertyImageResolution:
2923        parsedValue = parseImageResolution();
2924        break;
2925#endif
2926    case CSSPropertyBorderBottomStyle:
2927    case CSSPropertyBorderCollapse:
2928    case CSSPropertyBorderLeftStyle:
2929    case CSSPropertyBorderRightStyle:
2930    case CSSPropertyBorderTopStyle:
2931    case CSSPropertyBoxSizing:
2932    case CSSPropertyCaptionSide:
2933    case CSSPropertyClear:
2934    case CSSPropertyDirection:
2935    case CSSPropertyDisplay:
2936    case CSSPropertyEmptyCells:
2937    case CSSPropertyFloat:
2938    case CSSPropertyFontStyle:
2939    case CSSPropertyImageRendering:
2940    case CSSPropertyListStylePosition:
2941    case CSSPropertyListStyleType:
2942    case CSSPropertyObjectFit:
2943    case CSSPropertyOutlineStyle:
2944    case CSSPropertyOverflowWrap:
2945    case CSSPropertyOverflowX:
2946    case CSSPropertyOverflowY:
2947    case CSSPropertyPageBreakAfter:
2948    case CSSPropertyPageBreakBefore:
2949    case CSSPropertyPageBreakInside:
2950    case CSSPropertyPointerEvents:
2951    case CSSPropertyPosition:
2952    case CSSPropertyResize:
2953    case CSSPropertySpeak:
2954    case CSSPropertyTableLayout:
2955    case CSSPropertyTextLineThroughMode:
2956    case CSSPropertyTextLineThroughStyle:
2957    case CSSPropertyTextOverflow:
2958    case CSSPropertyTextOverlineMode:
2959    case CSSPropertyTextOverlineStyle:
2960    case CSSPropertyTextRendering:
2961    case CSSPropertyTextTransform:
2962    case CSSPropertyTextUnderlineMode:
2963    case CSSPropertyTextUnderlineStyle:
2964    case CSSPropertyVisibility:
2965    case CSSPropertyWebkitAppearance:
2966    case CSSPropertyWebkitBackfaceVisibility:
2967    case CSSPropertyWebkitBorderAfterStyle:
2968    case CSSPropertyWebkitBorderBeforeStyle:
2969    case CSSPropertyWebkitBorderEndStyle:
2970    case CSSPropertyWebkitBorderFit:
2971    case CSSPropertyWebkitBorderStartStyle:
2972    case CSSPropertyWebkitBoxAlign:
2973#if ENABLE(CSS_BOX_DECORATION_BREAK)
2974    case CSSPropertyWebkitBoxDecorationBreak:
2975#endif
2976    case CSSPropertyWebkitBoxDirection:
2977    case CSSPropertyWebkitBoxLines:
2978    case CSSPropertyWebkitBoxOrient:
2979    case CSSPropertyWebkitBoxPack:
2980    case CSSPropertyWebkitColorCorrection:
2981    case CSSPropertyWebkitColumnBreakAfter:
2982    case CSSPropertyWebkitColumnBreakBefore:
2983    case CSSPropertyWebkitColumnBreakInside:
2984    case CSSPropertyWebkitColumnFill:
2985    case CSSPropertyWebkitColumnRuleStyle:
2986    case CSSPropertyWebkitAlignContent:
2987    case CSSPropertyWebkitAlignItems:
2988    case CSSPropertyWebkitAlignSelf:
2989    case CSSPropertyWebkitFlexDirection:
2990    case CSSPropertyWebkitFlexWrap:
2991    case CSSPropertyWebkitJustifyContent:
2992    case CSSPropertyWebkitFontKerning:
2993    case CSSPropertyWebkitFontSmoothing:
2994    case CSSPropertyWebkitHyphens:
2995    case CSSPropertyWebkitLineAlign:
2996    case CSSPropertyWebkitLineBreak:
2997    case CSSPropertyWebkitLineSnap:
2998    case CSSPropertyWebkitMarginAfterCollapse:
2999    case CSSPropertyWebkitMarginBeforeCollapse:
3000    case CSSPropertyWebkitMarginBottomCollapse:
3001    case CSSPropertyWebkitMarginTopCollapse:
3002    case CSSPropertyWebkitMarqueeDirection:
3003    case CSSPropertyWebkitMarqueeStyle:
3004    case CSSPropertyWebkitNbspMode:
3005#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
3006    case CSSPropertyWebkitOverflowScrolling:
3007#endif
3008    case CSSPropertyWebkitPrintColorAdjust:
3009#if ENABLE(CSS_REGIONS)
3010    case CSSPropertyWebkitRegionBreakAfter:
3011    case CSSPropertyWebkitRegionBreakBefore:
3012    case CSSPropertyWebkitRegionBreakInside:
3013    case CSSPropertyWebkitRegionFragment:
3014#endif
3015    case CSSPropertyWebkitRtlOrdering:
3016    case CSSPropertyWebkitRubyPosition:
3017#if ENABLE(CSS3_TEXT)
3018    case CSSPropertyWebkitTextAlignLast:
3019#endif // CSS3_TEXT
3020    case CSSPropertyWebkitTextCombine:
3021#if ENABLE(CSS3_TEXT)
3022    case CSSPropertyWebkitTextJustify:
3023#endif // CSS3_TEXT
3024    case CSSPropertyWebkitTextSecurity:
3025    case CSSPropertyWebkitTransformStyle:
3026    case CSSPropertyWebkitUserDrag:
3027    case CSSPropertyWebkitUserModify:
3028    case CSSPropertyWebkitUserSelect:
3029    case CSSPropertyWebkitWritingMode:
3030    case CSSPropertyWhiteSpace:
3031    case CSSPropertyWordBreak:
3032    case CSSPropertyWordWrap:
3033        // These properties should be handled before in isValidKeywordPropertyAndValue().
3034        ASSERT_NOT_REACHED();
3035        return false;
3036#if ENABLE(CSS_DEVICE_ADAPTATION)
3037    // Properties bellow are validated inside parseViewportProperty, because we
3038    // check for parser state inViewportScope. We need to invalidate if someone
3039    // adds them outside a @viewport rule.
3040    case CSSPropertyMaxZoom:
3041    case CSSPropertyMinZoom:
3042    case CSSPropertyOrientation:
3043    case CSSPropertyUserZoom:
3044        validPrimitive = false;
3045        break;
3046#endif
3047    default:
3048        return parseSVGValue(propId, important);
3049    }
3050
3051    if (validPrimitive) {
3052        parsedValue = parseValidPrimitive(id, value);
3053        m_valueList->next();
3054    }
3055    ASSERT(!m_parsedCalculation);
3056    if (parsedValue) {
3057        if (!m_valueList->current() || inShorthand()) {
3058            addProperty(propId, parsedValue.release(), important);
3059            return true;
3060        }
3061    }
3062    return false;
3063}
3064
3065void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
3066{
3067    if (lval) {
3068        if (lval->isBaseValueList())
3069            toCSSValueList(lval.get())->append(rval);
3070        else {
3071            PassRefPtr<CSSValue> oldlVal(lval.release());
3072            PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
3073            list->append(oldlVal);
3074            list->append(rval);
3075            lval = list;
3076        }
3077    }
3078    else
3079        lval = rval;
3080}
3081
3082static bool isItemPositionKeyword(CSSValueID id)
3083{
3084    return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
3085        || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
3086        || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight;
3087}
3088
3089bool CSSParser::parseJustifySelf(CSSPropertyID propId, bool important)
3090{
3091    // auto | baseline | stretch | [<item-position> && <overflow-position>? ]
3092    // <item-position> = center | start | end | self-start | self-end | flex-start | flex-end | left | right;
3093    // <overflow-position> = true | safe
3094
3095    CSSParserValue* value = m_valueList->current();
3096
3097    if (value->id == CSSValueAuto || value->id == CSSValueBaseline || value->id == CSSValueStretch) {
3098        if (m_valueList->next())
3099            return false;
3100
3101        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
3102        return true;
3103    }
3104
3105    RefPtr<CSSPrimitiveValue> position = 0;
3106    RefPtr<CSSPrimitiveValue> overflowAlignmentKeyword = 0;
3107    if (isItemPositionKeyword(value->id)) {
3108        position = cssValuePool().createIdentifierValue(value->id);
3109        value = m_valueList->next();
3110        if (value) {
3111            if (value->id != CSSValueTrue && value->id != CSSValueSafe)
3112                return false;
3113            overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
3114        }
3115    } else if (value->id != CSSValueTrue && value->id != CSSValueSafe)
3116        return false;
3117    else {
3118        overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
3119        value = m_valueList->next();
3120        if (value) {
3121            if (!isItemPositionKeyword(value->id))
3122                return false;
3123            position = cssValuePool().createIdentifierValue(value->id);
3124        }
3125    }
3126
3127    if (m_valueList->next())
3128        return false;
3129
3130    ASSERT(position);
3131    if (overflowAlignmentKeyword)
3132        addProperty(propId, createPrimitiveValuePair(position.release(), overflowAlignmentKeyword.release()), important);
3133    else
3134        addProperty(propId, position.release(), important);
3135
3136    return true;
3137}
3138
3139static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue)
3140{
3141    if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
3142        || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
3143        cssValue = cssValuePool().createIdentifierValue(parserValue->id);
3144        return true;
3145    }
3146    return false;
3147}
3148
3149bool CSSParser::useLegacyBackgroundSizeShorthandBehavior() const
3150{
3151    return m_context.useLegacyBackgroundSizeShorthandBehavior;
3152}
3153
3154const int cMaxFillProperties = 9;
3155
3156bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
3157{
3158    ASSERT(numProperties <= cMaxFillProperties);
3159    if (numProperties > cMaxFillProperties)
3160        return false;
3161
3162    ShorthandScope scope(this, propId);
3163
3164    bool parsedProperty[cMaxFillProperties] = { false };
3165    RefPtr<CSSValue> values[cMaxFillProperties];
3166    RefPtr<CSSValue> clipValue;
3167    RefPtr<CSSValue> positionYValue;
3168    RefPtr<CSSValue> repeatYValue;
3169    bool foundClip = false;
3170    int i;
3171    bool foundPositionCSSProperty = false;
3172
3173    while (m_valueList->current()) {
3174        CSSParserValue* val = m_valueList->current();
3175        if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3176            // We hit the end.  Fill in all remaining values with the initial value.
3177            m_valueList->next();
3178            for (i = 0; i < numProperties; ++i) {
3179                if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
3180                    // Color is not allowed except as the last item in a list for backgrounds.
3181                    // Reject the entire property.
3182                    return false;
3183
3184                if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
3185                    addFillValue(values[i], cssValuePool().createImplicitInitialValue());
3186                    if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
3187                        addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
3188                    if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
3189                        addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
3190                    if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
3191                        // If background-origin wasn't present, then reset background-clip also.
3192                        addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
3193                    }
3194                }
3195                parsedProperty[i] = false;
3196            }
3197            if (!m_valueList->current())
3198                break;
3199        }
3200
3201        bool sizeCSSPropertyExpected = false;
3202        if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
3203            sizeCSSPropertyExpected = true;
3204            m_valueList->next();
3205        }
3206
3207        foundPositionCSSProperty = false;
3208        bool found = false;
3209        for (i = 0; !found && i < numProperties; ++i) {
3210
3211            if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgroundSize && properties[i] != CSSPropertyWebkitMaskSize))
3212                continue;
3213            if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgroundSize || properties[i] == CSSPropertyWebkitMaskSize))
3214                continue;
3215
3216            if (!parsedProperty[i]) {
3217                RefPtr<CSSValue> val1;
3218                RefPtr<CSSValue> val2;
3219                CSSPropertyID propId1, propId2;
3220                CSSParserValue* parserValue = m_valueList->current();
3221                if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
3222                    parsedProperty[i] = found = true;
3223                    addFillValue(values[i], val1.release());
3224                    if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
3225                        addFillValue(positionYValue, val2.release());
3226                    if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
3227                        addFillValue(repeatYValue, val2.release());
3228                    if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
3229                        // Reparse the value as a clip, and see if we succeed.
3230                        if (parseBackgroundClip(parserValue, val1))
3231                            addFillValue(clipValue, val1.release()); // The property parsed successfully.
3232                        else
3233                            addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
3234                    }
3235                    if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip)
3236                        foundClip = true;
3237                    if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
3238                        foundPositionCSSProperty = true;
3239                }
3240            }
3241        }
3242
3243        // if we didn't find at least one match, this is an
3244        // invalid shorthand and we have to ignore it
3245        if (!found)
3246            return false;
3247    }
3248
3249    // Now add all of the properties we found.
3250    for (i = 0; i < numProperties; i++) {
3251        // Fill in any remaining properties with the initial value.
3252        if (!parsedProperty[i]) {
3253            addFillValue(values[i], cssValuePool().createImplicitInitialValue());
3254            if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
3255                addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
3256            if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
3257                addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
3258            if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
3259                // If background-origin wasn't present, then reset background-clip also.
3260                addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
3261            }
3262        }
3263        if (properties[i] == CSSPropertyBackgroundPosition) {
3264            addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
3265            // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
3266            addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
3267        } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
3268            addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
3269            // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
3270            addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
3271        } else if (properties[i] == CSSPropertyBackgroundRepeat) {
3272            addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
3273            // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
3274            addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
3275        } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
3276            addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
3277            // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
3278            addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
3279        } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
3280            // Value is already set while updating origin
3281            continue;
3282        else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i] && useLegacyBackgroundSizeShorthandBehavior())
3283            continue;
3284        else
3285            addProperty(properties[i], values[i].release(), important);
3286
3287        // Add in clip values when we hit the corresponding origin property.
3288        if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
3289            addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
3290        else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
3291            addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
3292    }
3293
3294    return true;
3295}
3296
3297void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
3298{
3299    if (lval) {
3300        if (lval->isValueList())
3301            toCSSValueList(lval.get())->append(rval);
3302        else {
3303            PassRefPtr<CSSValue> oldVal(lval.release());
3304            PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
3305            list->append(oldVal);
3306            list->append(rval);
3307            lval = list;
3308        }
3309    }
3310    else
3311        lval = rval;
3312}
3313
3314bool CSSParser::parseAnimationShorthand(bool important)
3315{
3316    const StylePropertyShorthand& animationProperties = webkitAnimationShorthandForParsing();
3317    const unsigned numProperties = 7;
3318
3319    // The list of properties in the shorthand should be the same
3320    // length as the list with animation name in last position, even though they are
3321    // in a different order.
3322    ASSERT(numProperties == webkitAnimationShorthandForParsing().length());
3323    ASSERT(numProperties == webkitAnimationShorthand().length());
3324
3325    ShorthandScope scope(this, CSSPropertyWebkitAnimation);
3326
3327    bool parsedProperty[numProperties] = { false };
3328    AnimationParseContext context;
3329    RefPtr<CSSValue> values[numProperties];
3330
3331    unsigned i;
3332    while (m_valueList->current()) {
3333        CSSParserValue* val = m_valueList->current();
3334        if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3335            // We hit the end.  Fill in all remaining values with the initial value.
3336            m_valueList->next();
3337            for (i = 0; i < numProperties; ++i) {
3338                if (!parsedProperty[i])
3339                    addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3340                parsedProperty[i] = false;
3341            }
3342            if (!m_valueList->current())
3343                break;
3344            context.commitFirstAnimation();
3345        }
3346
3347        bool found = false;
3348        for (i = 0; i < numProperties; ++i) {
3349            if (!parsedProperty[i]) {
3350                RefPtr<CSSValue> val;
3351                if (parseAnimationProperty(animationProperties.properties()[i], val, context)) {
3352                    parsedProperty[i] = found = true;
3353                    addAnimationValue(values[i], val.release());
3354                    break;
3355                }
3356            }
3357
3358            // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid.
3359            if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation())
3360                return false;
3361        }
3362
3363        // if we didn't find at least one match, this is an
3364        // invalid shorthand and we have to ignore it
3365        if (!found)
3366            return false;
3367    }
3368
3369    for (i = 0; i < numProperties; ++i) {
3370        // If we didn't find the property, set an intial value.
3371        if (!parsedProperty[i])
3372            addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3373
3374        addProperty(animationProperties.properties()[i], values[i].release(), important);
3375    }
3376
3377    return true;
3378}
3379
3380bool CSSParser::parseTransitionShorthand(CSSPropertyID propId, bool important)
3381{
3382    const unsigned numProperties = 4;
3383    const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
3384    ASSERT(numProperties == shorthand.length());
3385
3386    ShorthandScope scope(this, propId);
3387
3388    bool parsedProperty[numProperties] = { false };
3389    AnimationParseContext context;
3390    RefPtr<CSSValue> values[numProperties];
3391
3392    unsigned i;
3393    while (m_valueList->current()) {
3394        CSSParserValue* val = m_valueList->current();
3395        if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3396            // We hit the end. Fill in all remaining values with the initial value.
3397            m_valueList->next();
3398            for (i = 0; i < numProperties; ++i) {
3399                if (!parsedProperty[i])
3400                    addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3401                parsedProperty[i] = false;
3402            }
3403            if (!m_valueList->current())
3404                break;
3405            context.commitFirstAnimation();
3406        }
3407
3408        bool found = false;
3409        for (i = 0; !found && i < numProperties; ++i) {
3410            if (!parsedProperty[i]) {
3411                RefPtr<CSSValue> val;
3412                if (parseAnimationProperty(shorthand.properties()[i], val, context)) {
3413                    parsedProperty[i] = found = true;
3414                    addAnimationValue(values[i], val.release());
3415                }
3416
3417                // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid.
3418                if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation())
3419                    return false;
3420            }
3421        }
3422
3423        // if we didn't find at least one match, this is an
3424        // invalid shorthand and we have to ignore it
3425        if (!found)
3426            return false;
3427    }
3428
3429    // Fill in any remaining properties with the initial value.
3430    for (i = 0; i < numProperties; ++i) {
3431        if (!parsedProperty[i])
3432            addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3433    }
3434
3435    // Now add all of the properties we found.
3436    for (i = 0; i < numProperties; i++)
3437        addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].release(), important);
3438
3439    return true;
3440}
3441
3442bool CSSParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
3443{
3444    // We try to match as many properties as possible
3445    // We set up an array of booleans to mark which property has been found,
3446    // and we try to search for properties until it makes no longer any sense.
3447    ShorthandScope scope(this, propId);
3448
3449    bool found = false;
3450    unsigned propertiesParsed = 0;
3451    bool propertyFound[6]= { false, false, false, false, false, false }; // 6 is enough size.
3452
3453    while (m_valueList->current()) {
3454        found = false;
3455        for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
3456            if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
3457                    propertyFound[propIndex] = found = true;
3458                    propertiesParsed++;
3459            }
3460        }
3461
3462        // if we didn't find at least one match, this is an
3463        // invalid shorthand and we have to ignore it
3464        if (!found)
3465            return false;
3466    }
3467
3468    if (propertiesParsed == shorthand.length())
3469        return true;
3470
3471    // Fill in any remaining properties with the initial value.
3472    ImplicitScope implicitScope(this, PropertyImplicit);
3473    const StylePropertyShorthand* propertiesForInitialization = shorthand.propertiesForInitialization();
3474    for (unsigned i = 0; i < shorthand.length(); ++i) {
3475        if (propertyFound[i])
3476            continue;
3477
3478        if (propertiesForInitialization) {
3479            const StylePropertyShorthand& initProperties = propertiesForInitialization[i];
3480            for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
3481                addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
3482        } else
3483            addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
3484    }
3485
3486    return true;
3487}
3488
3489bool CSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties,  bool important)
3490{
3491    /* From the CSS 2 specs, 8.3
3492     * If there is only one value, it applies to all sides. If there are two values, the top and
3493     * bottom margins are set to the first value and the right and left margins are set to the second.
3494     * If there are three values, the top is set to the first value, the left and right are set to the
3495     * second, and the bottom is set to the third. If there are four values, they apply to the top,
3496     * right, bottom, and left, respectively.
3497     */
3498
3499    unsigned num = inShorthand() ? 1 : m_valueList->size();
3500
3501    ShorthandScope scope(this, propId);
3502
3503    // the order is top, right, bottom, left
3504    switch (num) {
3505        case 1: {
3506            if (!parseValue(properties[0], important))
3507                return false;
3508            CSSValue* value = m_parsedProperties.last().value();
3509            ImplicitScope implicitScope(this, PropertyImplicit);
3510            addProperty(properties[1], value, important);
3511            addProperty(properties[2], value, important);
3512            addProperty(properties[3], value, important);
3513            break;
3514        }
3515        case 2: {
3516            if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
3517                return false;
3518            CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3519            ImplicitScope implicitScope(this, PropertyImplicit);
3520            addProperty(properties[2], value, important);
3521            value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3522            addProperty(properties[3], value, important);
3523            break;
3524        }
3525        case 3: {
3526            if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
3527                return false;
3528            CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3529            ImplicitScope implicitScope(this, PropertyImplicit);
3530            addProperty(properties[3], value, important);
3531            break;
3532        }
3533        case 4: {
3534            if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
3535                !parseValue(properties[2], important) || !parseValue(properties[3], important))
3536                return false;
3537            break;
3538        }
3539        default: {
3540            return false;
3541        }
3542    }
3543
3544    return true;
3545}
3546
3547// auto | <identifier>
3548bool CSSParser::parsePage(CSSPropertyID propId, bool important)
3549{
3550    ASSERT(propId == CSSPropertyPage);
3551
3552    if (m_valueList->size() != 1)
3553        return false;
3554
3555    CSSParserValue* value = m_valueList->current();
3556    if (!value)
3557        return false;
3558
3559    if (value->id == CSSValueAuto) {
3560        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
3561        return true;
3562    } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
3563        addProperty(propId, createPrimitiveStringValue(value), important);
3564        return true;
3565    }
3566    return false;
3567}
3568
3569// <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
3570bool CSSParser::parseSize(CSSPropertyID propId, bool important)
3571{
3572    ASSERT(propId == CSSPropertySize);
3573
3574    if (m_valueList->size() > 2)
3575        return false;
3576
3577    CSSParserValue* value = m_valueList->current();
3578    if (!value)
3579        return false;
3580
3581    RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
3582
3583    // First parameter.
3584    SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
3585    if (paramType == None)
3586        return false;
3587
3588    // Second parameter, if any.
3589    value = m_valueList->next();
3590    if (value) {
3591        paramType = parseSizeParameter(parsedValues.get(), value, paramType);
3592        if (paramType == None)
3593            return false;
3594    }
3595
3596    addProperty(propId, parsedValues.release(), important);
3597    return true;
3598}
3599
3600CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
3601{
3602    switch (value->id) {
3603    case CSSValueAuto:
3604        if (prevParamType == None) {
3605            parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3606            return Auto;
3607        }
3608        return None;
3609    case CSSValueLandscape:
3610    case CSSValuePortrait:
3611        if (prevParamType == None || prevParamType == PageSize) {
3612            parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3613            return Orientation;
3614        }
3615        return None;
3616    case CSSValueA3:
3617    case CSSValueA4:
3618    case CSSValueA5:
3619    case CSSValueB4:
3620    case CSSValueB5:
3621    case CSSValueLedger:
3622    case CSSValueLegal:
3623    case CSSValueLetter:
3624        if (prevParamType == None || prevParamType == Orientation) {
3625            // Normalize to Page Size then Orientation order by prepending.
3626            // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
3627            parsedValues->prepend(cssValuePool().createIdentifierValue(value->id));
3628            return PageSize;
3629        }
3630        return None;
3631    case 0:
3632        if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) {
3633            parsedValues->append(createPrimitiveNumericValue(value));
3634            return Length;
3635        }
3636        return None;
3637    default:
3638        return None;
3639    }
3640}
3641
3642// [ <string> <string> ]+ | inherit | none
3643// inherit and none are handled in parseValue.
3644bool CSSParser::parseQuotes(CSSPropertyID propId, bool important)
3645{
3646    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3647    while (CSSParserValue* val = m_valueList->current()) {
3648        RefPtr<CSSValue> parsedValue;
3649        if (val->unit == CSSPrimitiveValue::CSS_STRING)
3650            parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
3651        else
3652            break;
3653        values->append(parsedValue.release());
3654        m_valueList->next();
3655    }
3656    if (values->length()) {
3657        addProperty(propId, values.release(), important);
3658        m_valueList->next();
3659        return true;
3660    }
3661    return false;
3662}
3663
3664bool CSSParser::parseAlt(CSSPropertyID propID, bool important)
3665{
3666    CSSParserValue* val = m_valueList->current();
3667    RefPtr<CSSValue> parsedValue;
3668
3669    if (val->unit == CSSPrimitiveValue::CSS_STRING)
3670        parsedValue = createPrimitiveStringValue(val);
3671    else if (val->unit == CSSParserValue::Function) {
3672        CSSParserValueList* args = val->function->args.get();
3673        if (!args)
3674            return false;
3675        if (equalIgnoringCase(val->function->name, "attr("))
3676            parsedValue = parseAttr(args);
3677    }
3678
3679    if (parsedValue) {
3680        addProperty(propID, parsedValue.release(), important);
3681        m_valueList->next();
3682        return true;
3683    }
3684
3685    return false;
3686}
3687
3688// [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
3689// in CSS 2.1 this got somewhat reduced:
3690// [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
3691bool CSSParser::parseContent(CSSPropertyID propId, bool important)
3692{
3693    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3694
3695    while (CSSParserValue* val = m_valueList->current()) {
3696        RefPtr<CSSValue> parsedValue;
3697        if (val->unit == CSSPrimitiveValue::CSS_URI) {
3698            // url
3699            parsedValue = CSSImageValue::create(completeURL(val->string));
3700        } else if (val->unit == CSSParserValue::Function) {
3701            // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
3702            CSSParserValueList* args = val->function->args.get();
3703            if (!args)
3704                return false;
3705            if (equalIgnoringCase(val->function->name, "attr(")) {
3706                parsedValue = parseAttr(args);
3707                if (!parsedValue)
3708                    return false;
3709            } else if (equalIgnoringCase(val->function->name, "counter(")) {
3710                parsedValue = parseCounterContent(args, false);
3711                if (!parsedValue)
3712                    return false;
3713            } else if (equalIgnoringCase(val->function->name, "counters(")) {
3714                parsedValue = parseCounterContent(args, true);
3715                if (!parsedValue)
3716                    return false;
3717#if ENABLE(CSS_IMAGE_SET)
3718            } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
3719                parsedValue = parseImageSet();
3720                if (!parsedValue)
3721                    return false;
3722#endif
3723            } else if (isGeneratedImageValue(val)) {
3724                if (!parseGeneratedImage(m_valueList.get(), parsedValue))
3725                    return false;
3726            } else
3727                return false;
3728        } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
3729            // open-quote
3730            // close-quote
3731            // no-open-quote
3732            // no-close-quote
3733            // inherit
3734            // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
3735            // none
3736            // normal
3737            switch (val->id) {
3738            case CSSValueOpenQuote:
3739            case CSSValueCloseQuote:
3740            case CSSValueNoOpenQuote:
3741            case CSSValueNoCloseQuote:
3742            case CSSValueNone:
3743            case CSSValueNormal:
3744                parsedValue = cssValuePool().createIdentifierValue(val->id);
3745                break;
3746            default:
3747                break;
3748            }
3749        } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
3750            parsedValue = createPrimitiveStringValue(val);
3751        }
3752        if (!parsedValue)
3753            break;
3754        values->append(parsedValue.release());
3755        m_valueList->next();
3756    }
3757
3758    if (values->length()) {
3759        addProperty(propId, values.release(), important);
3760        m_valueList->next();
3761        return true;
3762    }
3763
3764    return false;
3765}
3766
3767PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args)
3768{
3769    if (args->size() != 1)
3770        return 0;
3771
3772    CSSParserValue* a = args->current();
3773
3774    if (a->unit != CSSPrimitiveValue::CSS_IDENT)
3775        return 0;
3776
3777    String attrName = a->string;
3778    // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
3779    // But HTML attribute names can't have those characters, and we should not
3780    // even parse them inside attr().
3781    if (attrName[0] == '-')
3782        return 0;
3783
3784    if (m_context.isHTMLDocument)
3785        attrName = attrName.lower();
3786
3787    return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
3788}
3789
3790PassRefPtr<CSSValue> CSSParser::parseBackgroundColor()
3791{
3792    CSSValueID id = m_valueList->current()->id;
3793    if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
3794        (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
3795        return cssValuePool().createIdentifierValue(id);
3796    return parseColor();
3797}
3798
3799bool CSSParser::parseFillImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
3800{
3801    if (valueList->current()->id == CSSValueNone) {
3802        value = cssValuePool().createIdentifierValue(CSSValueNone);
3803        return true;
3804    }
3805    if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
3806        value = CSSImageValue::create(completeURL(valueList->current()->string));
3807        return true;
3808    }
3809
3810    if (isGeneratedImageValue(valueList->current()))
3811        return parseGeneratedImage(valueList, value);
3812
3813#if ENABLE(CSS_IMAGE_SET)
3814    if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) {
3815        value = parseImageSet();
3816        if (value)
3817            return true;
3818    }
3819#endif
3820
3821    return false;
3822}
3823
3824PassRefPtr<CSSValue> CSSParser::parseFillPositionX(CSSParserValueList* valueList)
3825{
3826    int id = valueList->current()->id;
3827    if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
3828        int percent = 0;
3829        if (id == CSSValueRight)
3830            percent = 100;
3831        else if (id == CSSValueCenter)
3832            percent = 50;
3833        return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3834    }
3835    if (validUnit(valueList->current(), FPercent | FLength))
3836        return createPrimitiveNumericValue(valueList->current());
3837    return 0;
3838}
3839
3840PassRefPtr<CSSValue> CSSParser::parseFillPositionY(CSSParserValueList* valueList)
3841{
3842    int id = valueList->current()->id;
3843    if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
3844        int percent = 0;
3845        if (id == CSSValueBottom)
3846            percent = 100;
3847        else if (id == CSSValueCenter)
3848            percent = 50;
3849        return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3850    }
3851    if (validUnit(valueList->current(), FPercent | FLength))
3852        return createPrimitiveNumericValue(valueList->current());
3853    return 0;
3854}
3855
3856PassRefPtr<CSSPrimitiveValue> CSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode)
3857{
3858    CSSValueID id = valueList->current()->id;
3859    if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
3860        int percent = 0;
3861        if (id == CSSValueLeft || id == CSSValueRight) {
3862            if (cumulativeFlags & XFillPosition)
3863                return 0;
3864            cumulativeFlags |= XFillPosition;
3865            individualFlag = XFillPosition;
3866            if (id == CSSValueRight)
3867                percent = 100;
3868        }
3869        else if (id == CSSValueTop || id == CSSValueBottom) {
3870            if (cumulativeFlags & YFillPosition)
3871                return 0;
3872            cumulativeFlags |= YFillPosition;
3873            individualFlag = YFillPosition;
3874            if (id == CSSValueBottom)
3875                percent = 100;
3876        } else if (id == CSSValueCenter) {
3877            // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
3878            percent = 50;
3879            cumulativeFlags |= AmbiguousFillPosition;
3880            individualFlag = AmbiguousFillPosition;
3881        }
3882
3883        if (parsingMode == ResolveValuesAsKeyword)
3884            return cssValuePool().createIdentifierValue(id);
3885
3886        return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3887    }
3888    if (validUnit(valueList->current(), FPercent | FLength)) {
3889        if (!cumulativeFlags) {
3890            cumulativeFlags |= XFillPosition;
3891            individualFlag = XFillPosition;
3892        } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
3893            cumulativeFlags |= YFillPosition;
3894            individualFlag = YFillPosition;
3895        } else {
3896            if (m_parsedCalculation)
3897                m_parsedCalculation.release();
3898            return 0;
3899        }
3900        return createPrimitiveNumericValue(valueList->current());
3901    }
3902    return 0;
3903}
3904
3905static bool isValueConflictingWithCurrentEdge(int value1, int value2)
3906{
3907    if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSValueLeft || value2 == CSSValueRight))
3908        return true;
3909
3910    if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSValueTop || value2 == CSSValueBottom))
3911        return true;
3912
3913    return false;
3914}
3915
3916static bool isFillPositionKeyword(CSSValueID value)
3917{
3918    return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter;
3919}
3920
3921void CSSParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtr<CSSPrimitiveValue> parsedValue1, PassRefPtr<CSSPrimitiveValue> parsedValue2)
3922{
3923    // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <percentage> | <length> ]
3924    // In the case of 4 values <position> requires the second value to be a length or a percentage.
3925    if (isFillPositionKeyword(parsedValue2->getValueID()))
3926        return;
3927
3928    unsigned cumulativeFlags = 0;
3929    FillPositionFlag value3Flag = InvalidFillPosition;
3930    RefPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
3931    if (!value3)
3932        return;
3933
3934    CSSValueID ident1 = parsedValue1->getValueID();
3935    CSSValueID ident3 = value3->getValueID();
3936
3937    if (ident1 == CSSValueCenter)
3938        return;
3939
3940    if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
3941        return;
3942
3943    // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
3944    // needed as the second call to parseFillPositionComponent was on purpose not checking it. In the
3945    // case of two values top 20px is invalid but in the case of 4 values it becomes valid.
3946    if (isValueConflictingWithCurrentEdge(ident1, ident3))
3947        return;
3948
3949    valueList->next();
3950
3951    cumulativeFlags = 0;
3952    FillPositionFlag value4Flag = InvalidFillPosition;
3953    RefPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(valueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
3954    if (!value4)
3955        return;
3956
3957    // 4th value must be a length or a percentage.
3958    if (isFillPositionKeyword(value4->getValueID()))
3959        return;
3960
3961    value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
3962    value2 = createPrimitiveValuePair(value3, value4);
3963
3964    if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
3965        value1.swap(value2);
3966
3967    valueList->next();
3968}
3969void CSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtr<CSSPrimitiveValue> parsedValue1, PassRefPtr<CSSPrimitiveValue> parsedValue2)
3970{
3971    unsigned cumulativeFlags = 0;
3972    FillPositionFlag value3Flag = InvalidFillPosition;
3973    RefPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
3974
3975    // value3 is not an expected value, we return.
3976    if (!value3)
3977        return;
3978
3979    valueList->next();
3980
3981    bool swapNeeded = false;
3982    CSSValueID ident1 = parsedValue1->getValueID();
3983    CSSValueID ident2 = parsedValue2->getValueID();
3984    CSSValueID ident3 = value3->getValueID();
3985
3986    CSSValueID firstPositionKeyword;
3987    CSSValueID secondPositionKeyword;
3988
3989    if (ident1 == CSSValueCenter) {
3990        // <position> requires the first 'center' to be followed by a keyword.
3991        if (!isFillPositionKeyword(ident2))
3992            return;
3993
3994        // If 'center' is the first keyword then the last one needs to be a length.
3995        if (isFillPositionKeyword(ident3))
3996            return;
3997
3998        firstPositionKeyword = CSSValueLeft;
3999        if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
4000            firstPositionKeyword = CSSValueTop;
4001            swapNeeded = true;
4002        }
4003        value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
4004        value2 = createPrimitiveValuePair(parsedValue2, value3);
4005    } else if (ident3 == CSSValueCenter) {
4006        if (isFillPositionKeyword(ident2))
4007            return;
4008
4009        secondPositionKeyword = CSSValueTop;
4010        if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
4011            secondPositionKeyword = CSSValueLeft;
4012            swapNeeded = true;
4013        }
4014        value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
4015        value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
4016    } else {
4017        RefPtr<CSSPrimitiveValue> firstPositionValue;
4018        RefPtr<CSSPrimitiveValue> secondPositionValue;
4019
4020        if (isFillPositionKeyword(ident2)) {
4021            // To match CSS grammar, we should only accept: [ center | left | right | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ].
4022            ASSERT(ident2 != CSSValueCenter);
4023
4024            if (isFillPositionKeyword(ident3))
4025                return;
4026
4027            secondPositionValue = value3;
4028            secondPositionKeyword = ident2;
4029            firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
4030        } else {
4031            // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
4032            if (!isFillPositionKeyword(ident3))
4033                return;
4034
4035            firstPositionValue = parsedValue2;
4036            secondPositionKeyword = ident3;
4037            secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
4038        }
4039
4040        if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
4041            return;
4042
4043        value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue);
4044        value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue);
4045    }
4046
4047    if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
4048        value1.swap(value2);
4049
4050#ifndef NDEBUG
4051    CSSPrimitiveValue* first = toCSSPrimitiveValue(value1.get());
4052    CSSPrimitiveValue* second = toCSSPrimitiveValue(value2.get());
4053    ident1 = first->getPairValue()->first()->getValueID();
4054    ident2 = second->getPairValue()->first()->getValueID();
4055    ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
4056    ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
4057#endif
4058}
4059
4060inline bool CSSParser::isPotentialPositionValue(CSSParserValue* value)
4061{
4062    return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue);
4063}
4064
4065void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
4066{
4067    unsigned numberOfValues = 0;
4068    for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++numberOfValues) {
4069        CSSParserValue* current = valueList->valueAt(i);
4070        if (isComma(current) || !current || isForwardSlashOperator(current) || !isPotentialPositionValue(current))
4071            break;
4072    }
4073
4074    if (numberOfValues > 4)
4075        return;
4076
4077    // If we are parsing two values, we can safely call the CSS 2.1 parsing function and return.
4078    if (numberOfValues <= 2) {
4079        parse2ValuesFillPosition(valueList, value1, value2);
4080        return;
4081    }
4082
4083    ASSERT(numberOfValues > 2 && numberOfValues <= 4);
4084
4085    CSSParserValue* value = valueList->current();
4086
4087    // <position> requires the first value to be a background keyword.
4088    if (!isFillPositionKeyword(value->id))
4089        return;
4090
4091    // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
4092    unsigned cumulativeFlags = 0;
4093    FillPositionFlag value1Flag = InvalidFillPosition;
4094    FillPositionFlag value2Flag = InvalidFillPosition;
4095    value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
4096    if (!value1)
4097        return;
4098
4099    value = valueList->next();
4100
4101    // In case we are parsing more than two values, relax the check inside of parseFillPositionComponent. top 20px is
4102    // a valid start for <position>.
4103    cumulativeFlags = AmbiguousFillPosition;
4104    value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
4105    if (value2)
4106        valueList->next();
4107    else {
4108        value1.clear();
4109        return;
4110    }
4111
4112    RefPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(value1.get());
4113    RefPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(value2.get());
4114
4115    value1.clear();
4116    value2.clear();
4117
4118    // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
4119    if (parsedValue2->getValueID() == CSSValueCenter)
4120        return;
4121
4122    if (numberOfValues == 3)
4123        parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
4124    else
4125        parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
4126}
4127
4128void CSSParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
4129{
4130    CSSParserValue* value = valueList->current();
4131
4132    // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
4133    unsigned cumulativeFlags = 0;
4134    FillPositionFlag value1Flag = InvalidFillPosition;
4135    FillPositionFlag value2Flag = InvalidFillPosition;
4136    value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
4137    if (!value1)
4138        return;
4139
4140    // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
4141    // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
4142    // value was explicitly specified for our property.
4143    value = valueList->next();
4144
4145    // First check for the comma.  If so, we are finished parsing this value or value pair.
4146    if (isComma(value))
4147        value = 0;
4148
4149    if (value) {
4150        value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
4151        if (value2)
4152            valueList->next();
4153        else {
4154            if (!inShorthand()) {
4155                value1.clear();
4156                return;
4157            }
4158        }
4159    }
4160
4161    if (!value2)
4162        // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
4163        // is simply 50%. This is our default.
4164        // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
4165        // For left/right/center, the default of 50% in the y is still correct.
4166        value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
4167
4168    if (value1Flag == YFillPosition || value2Flag == XFillPosition)
4169        value1.swap(value2);
4170}
4171
4172void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
4173{
4174    CSSValueID id = m_valueList->current()->id;
4175    if (id == CSSValueRepeatX) {
4176        m_implicitShorthand = true;
4177        value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
4178        value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
4179        m_valueList->next();
4180        return;
4181    }
4182    if (id == CSSValueRepeatY) {
4183        m_implicitShorthand = true;
4184        value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
4185        value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
4186        m_valueList->next();
4187        return;
4188    }
4189    if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
4190        value1 = cssValuePool().createIdentifierValue(id);
4191    else {
4192        value1 = 0;
4193        return;
4194    }
4195
4196    CSSParserValue* value = m_valueList->next();
4197
4198    // Parse the second value if one is available
4199    if (value && !isComma(value)) {
4200        id = value->id;
4201        if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
4202            value2 = cssValuePool().createIdentifierValue(id);
4203            m_valueList->next();
4204            return;
4205        }
4206    }
4207
4208    // If only one value was specified, value2 is the same as value1.
4209    m_implicitShorthand = true;
4210    value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get())->getValueID());
4211}
4212
4213PassRefPtr<CSSValue> CSSParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
4214{
4215    allowComma = true;
4216    CSSParserValue* value = m_valueList->current();
4217
4218    if (value->id == CSSValueContain || value->id == CSSValueCover)
4219        return cssValuePool().createIdentifierValue(value->id);
4220
4221    RefPtr<CSSPrimitiveValue> parsedValue1;
4222
4223    if (value->id == CSSValueAuto)
4224        parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
4225    else {
4226        if (!validUnit(value, FLength | FPercent))
4227            return 0;
4228        parsedValue1 = createPrimitiveNumericValue(value);
4229    }
4230
4231    RefPtr<CSSPrimitiveValue> parsedValue2;
4232    if ((value = m_valueList->next())) {
4233        if (value->unit == CSSParserValue::Operator && value->iValue == ',')
4234            allowComma = false;
4235        else if (value->id != CSSValueAuto) {
4236            if (!validUnit(value, FLength | FPercent)) {
4237                if (!inShorthand())
4238                    return 0;
4239                // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
4240                m_valueList->previous();
4241            } else
4242                parsedValue2 = createPrimitiveNumericValue(value);
4243        }
4244    } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
4245        // For backwards compatibility we set the second value to the first if it is omitted.
4246        // We only need to do this for -webkit-background-size. It should be safe to let masks match
4247        // the real property.
4248        parsedValue2 = parsedValue1;
4249    }
4250
4251    if (!parsedValue2)
4252        return parsedValue1;
4253    return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release());
4254}
4255
4256bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
4257                                  RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
4258{
4259    RefPtr<CSSValueList> values;
4260    RefPtr<CSSValueList> values2;
4261    CSSParserValue* val;
4262    RefPtr<CSSValue> value;
4263    RefPtr<CSSValue> value2;
4264
4265    bool allowComma = false;
4266
4267    retValue1 = retValue2 = 0;
4268    propId1 = propId;
4269    propId2 = propId;
4270    if (propId == CSSPropertyBackgroundPosition) {
4271        propId1 = CSSPropertyBackgroundPositionX;
4272        propId2 = CSSPropertyBackgroundPositionY;
4273    } else if (propId == CSSPropertyWebkitMaskPosition) {
4274        propId1 = CSSPropertyWebkitMaskPositionX;
4275        propId2 = CSSPropertyWebkitMaskPositionY;
4276    } else if (propId == CSSPropertyBackgroundRepeat) {
4277        propId1 = CSSPropertyBackgroundRepeatX;
4278        propId2 = CSSPropertyBackgroundRepeatY;
4279    } else if (propId == CSSPropertyWebkitMaskRepeat) {
4280        propId1 = CSSPropertyWebkitMaskRepeatX;
4281        propId2 = CSSPropertyWebkitMaskRepeatY;
4282    }
4283
4284    while ((val = m_valueList->current())) {
4285        RefPtr<CSSValue> currValue;
4286        RefPtr<CSSValue> currValue2;
4287
4288        if (allowComma) {
4289            if (!isComma(val))
4290                return false;
4291            m_valueList->next();
4292            allowComma = false;
4293        } else {
4294            allowComma = true;
4295            switch (propId) {
4296                case CSSPropertyBackgroundColor:
4297                    currValue = parseBackgroundColor();
4298                    if (currValue)
4299                        m_valueList->next();
4300                    break;
4301                case CSSPropertyBackgroundAttachment:
4302                    if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
4303                        currValue = cssValuePool().createIdentifierValue(val->id);
4304                        m_valueList->next();
4305                    }
4306                    break;
4307                case CSSPropertyBackgroundImage:
4308                case CSSPropertyWebkitMaskImage:
4309                    if (parseFillImage(m_valueList.get(), currValue))
4310                        m_valueList->next();
4311                    break;
4312                case CSSPropertyWebkitBackgroundClip:
4313                case CSSPropertyWebkitBackgroundOrigin:
4314                case CSSPropertyWebkitMaskClip:
4315                case CSSPropertyWebkitMaskOrigin:
4316                    // The first three values here are deprecated and do not apply to the version of the property that has
4317                    // the -webkit- prefix removed.
4318                    if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
4319                        val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
4320                        ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
4321                         (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
4322                        currValue = cssValuePool().createIdentifierValue(val->id);
4323                        m_valueList->next();
4324                    }
4325                    break;
4326                case CSSPropertyBackgroundClip:
4327                    if (parseBackgroundClip(val, currValue))
4328                        m_valueList->next();
4329                    break;
4330                case CSSPropertyBackgroundOrigin:
4331                    if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
4332                        currValue = cssValuePool().createIdentifierValue(val->id);
4333                        m_valueList->next();
4334                    }
4335                    break;
4336                case CSSPropertyBackgroundPosition:
4337                case CSSPropertyWebkitMaskPosition:
4338                    parseFillPosition(m_valueList.get(), currValue, currValue2);
4339                    // parseFillPosition advances the m_valueList pointer.
4340                    break;
4341                case CSSPropertyBackgroundPositionX:
4342                case CSSPropertyWebkitMaskPositionX: {
4343                    currValue = parseFillPositionX(m_valueList.get());
4344                    if (currValue)
4345                        m_valueList->next();
4346                    break;
4347                }
4348                case CSSPropertyBackgroundPositionY:
4349                case CSSPropertyWebkitMaskPositionY: {
4350                    currValue = parseFillPositionY(m_valueList.get());
4351                    if (currValue)
4352                        m_valueList->next();
4353                    break;
4354                }
4355                case CSSPropertyWebkitBackgroundComposite:
4356                case CSSPropertyWebkitMaskComposite:
4357                    if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) {
4358                        currValue = cssValuePool().createIdentifierValue(val->id);
4359                        m_valueList->next();
4360                    }
4361                    break;
4362                case CSSPropertyBackgroundBlendMode:
4363                    if (cssCompositingEnabled() && (val->id == CSSValueNormal || val->id == CSSValueMultiply
4364                        || val->id == CSSValueScreen || val->id == CSSValueOverlay || val->id == CSSValueDarken
4365                        || val->id == CSSValueLighten ||  val->id == CSSValueColorDodge || val->id == CSSValueColorBurn
4366                        || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference
4367                        || val->id == CSSValueExclusion)) {
4368                        currValue = cssValuePool().createIdentifierValue(val->id);
4369                        m_valueList->next();
4370                    }
4371                    break;
4372                case CSSPropertyBackgroundRepeat:
4373                case CSSPropertyWebkitMaskRepeat:
4374                    parseFillRepeat(currValue, currValue2);
4375                    // parseFillRepeat advances the m_valueList pointer
4376                    break;
4377                case CSSPropertyBackgroundSize:
4378                case CSSPropertyWebkitBackgroundSize:
4379                case CSSPropertyWebkitMaskSize: {
4380                    currValue = parseFillSize(propId, allowComma);
4381                    if (currValue)
4382                        m_valueList->next();
4383                    break;
4384                }
4385                case CSSPropertyWebkitMaskSourceType: {
4386                    if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id == CSSValueLuminance) {
4387                        currValue = cssValuePool().createIdentifierValue(val->id);
4388                        m_valueList->next();
4389                    } else
4390                        currValue = 0;
4391                    break;
4392                }
4393                default:
4394                    break;
4395            }
4396            if (!currValue)
4397                return false;
4398
4399            if (value && !values) {
4400                values = CSSValueList::createCommaSeparated();
4401                values->append(value.release());
4402            }
4403
4404            if (value2 && !values2) {
4405                values2 = CSSValueList::createCommaSeparated();
4406                values2->append(value2.release());
4407            }
4408
4409            if (values)
4410                values->append(currValue.release());
4411            else
4412                value = currValue.release();
4413            if (currValue2) {
4414                if (values2)
4415                    values2->append(currValue2.release());
4416                else
4417                    value2 = currValue2.release();
4418            }
4419        }
4420
4421        // When parsing any fill shorthand property, we let it handle building up the lists for all
4422        // properties.
4423        if (inShorthand())
4424            break;
4425    }
4426
4427    if (values && values->length()) {
4428        retValue1 = values.release();
4429        if (values2 && values2->length())
4430            retValue2 = values2.release();
4431        return true;
4432    }
4433    if (value) {
4434        retValue1 = value.release();
4435        retValue2 = value2.release();
4436        return true;
4437    }
4438    return false;
4439}
4440
4441PassRefPtr<CSSValue> CSSParser::parseAnimationDelay()
4442{
4443    CSSParserValue* value = m_valueList->current();
4444    if (validUnit(value, FTime))
4445        return createPrimitiveNumericValue(value);
4446    return 0;
4447}
4448
4449PassRefPtr<CSSValue> CSSParser::parseAnimationDirection()
4450{
4451    CSSParserValue* value = m_valueList->current();
4452    if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
4453        return cssValuePool().createIdentifierValue(value->id);
4454    return 0;
4455}
4456
4457PassRefPtr<CSSValue> CSSParser::parseAnimationDuration()
4458{
4459    CSSParserValue* value = m_valueList->current();
4460    if (validUnit(value, FTime | FNonNeg))
4461        return createPrimitiveNumericValue(value);
4462    return 0;
4463}
4464
4465PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode()
4466{
4467    CSSParserValue* value = m_valueList->current();
4468    if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
4469        return cssValuePool().createIdentifierValue(value->id);
4470    return 0;
4471}
4472
4473PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount()
4474{
4475    CSSParserValue* value = m_valueList->current();
4476    if (value->id == CSSValueInfinite)
4477        return cssValuePool().createIdentifierValue(value->id);
4478    if (validUnit(value, FNumber | FNonNeg))
4479        return createPrimitiveNumericValue(value);
4480    return 0;
4481}
4482
4483PassRefPtr<CSSValue> CSSParser::parseAnimationName()
4484{
4485    CSSParserValue* value = m_valueList->current();
4486    if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
4487        if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value, "none"))) {
4488            return cssValuePool().createIdentifierValue(CSSValueNone);
4489        } else {
4490            return createPrimitiveStringValue(value);
4491        }
4492    }
4493    return 0;
4494}
4495
4496PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState()
4497{
4498    CSSParserValue* value = m_valueList->current();
4499    if (value->id == CSSValueRunning || value->id == CSSValuePaused)
4500        return cssValuePool().createIdentifierValue(value->id);
4501    return 0;
4502}
4503
4504PassRefPtr<CSSValue> CSSParser::parseAnimationProperty(AnimationParseContext& context)
4505{
4506    CSSParserValue* value = m_valueList->current();
4507    if (value->unit != CSSPrimitiveValue::CSS_IDENT)
4508        return 0;
4509    CSSPropertyID result = cssPropertyID(value->string);
4510    if (result)
4511        return cssValuePool().createIdentifierValue(result);
4512    if (equalIgnoringCase(value, "all")) {
4513        context.sawAnimationPropertyKeyword();
4514        return cssValuePool().createIdentifierValue(CSSValueAll);
4515    }
4516    if (equalIgnoringCase(value, "none")) {
4517        context.commitAnimationPropertyKeyword();
4518        context.sawAnimationPropertyKeyword();
4519        return cssValuePool().createIdentifierValue(CSSValueNone);
4520    }
4521    return 0;
4522}
4523
4524bool CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
4525{
4526    parse2ValuesFillPosition(m_valueList.get(), value1, value2);
4527
4528    // now get z
4529    if (m_valueList->current()) {
4530        if (validUnit(m_valueList->current(), FLength)) {
4531            value3 = createPrimitiveNumericValue(m_valueList->current());
4532            m_valueList->next();
4533            return true;
4534        }
4535        return false;
4536    }
4537    value3 = cssValuePool().createImplicitInitialValue();
4538    return true;
4539}
4540
4541bool CSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
4542{
4543    CSSParserValue* v = args->current();
4544    if (!validUnit(v, FNumber))
4545        return false;
4546    result = v->fValue;
4547    v = args->next();
4548    if (!v)
4549        // The last number in the function has no comma after it, so we're done.
4550        return true;
4551    if (!isComma(v))
4552        return false;
4553    args->next();
4554    return true;
4555}
4556
4557PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction()
4558{
4559    CSSParserValue* value = m_valueList->current();
4560    if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
4561        || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd)
4562        return cssValuePool().createIdentifierValue(value->id);
4563
4564    // We must be a function.
4565    if (value->unit != CSSParserValue::Function)
4566        return 0;
4567
4568    CSSParserValueList* args = value->function->args.get();
4569
4570    if (equalIgnoringCase(value->function->name, "steps(")) {
4571        // For steps, 1 or 2 params must be specified (comma-separated)
4572        if (!args || (args->size() != 1 && args->size() != 3))
4573            return 0;
4574
4575        // There are two values.
4576        int numSteps;
4577        bool stepAtStart = false;
4578
4579        CSSParserValue* v = args->current();
4580        if (!validUnit(v, FInteger))
4581            return 0;
4582        numSteps = clampToInteger(v->fValue);
4583        if (numSteps < 1)
4584            return 0;
4585        v = args->next();
4586
4587        if (v) {
4588            // There is a comma so we need to parse the second value
4589            if (!isComma(v))
4590                return 0;
4591            v = args->next();
4592            if (v->id != CSSValueStart && v->id != CSSValueEnd)
4593                return 0;
4594            stepAtStart = v->id == CSSValueStart;
4595        }
4596
4597        return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart);
4598    }
4599
4600    if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
4601        // For cubic bezier, 4 values must be specified.
4602        if (!args || args->size() != 7)
4603            return 0;
4604
4605        // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range.
4606        double x1, y1, x2, y2;
4607
4608        if (!parseCubicBezierTimingFunctionValue(args, x1))
4609            return 0;
4610        if (x1 < 0 || x1 > 1)
4611            return 0;
4612        if (!parseCubicBezierTimingFunctionValue(args, y1))
4613            return 0;
4614        if (!parseCubicBezierTimingFunctionValue(args, x2))
4615            return 0;
4616        if (x2 < 0 || x2 > 1)
4617            return 0;
4618        if (!parseCubicBezierTimingFunctionValue(args, y2))
4619            return 0;
4620
4621        return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
4622    }
4623
4624    return 0;
4625}
4626
4627bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& result, AnimationParseContext& context)
4628{
4629    RefPtr<CSSValueList> values;
4630    CSSParserValue* val;
4631    RefPtr<CSSValue> value;
4632    bool allowComma = false;
4633
4634    result = 0;
4635
4636    while ((val = m_valueList->current())) {
4637        RefPtr<CSSValue> currValue;
4638        if (allowComma) {
4639            if (!isComma(val))
4640                return false;
4641            m_valueList->next();
4642            allowComma = false;
4643        }
4644        else {
4645            switch (propId) {
4646                case CSSPropertyWebkitAnimationDelay:
4647                case CSSPropertyTransitionDelay:
4648                case CSSPropertyWebkitTransitionDelay:
4649                    currValue = parseAnimationDelay();
4650                    if (currValue)
4651                        m_valueList->next();
4652                    break;
4653                case CSSPropertyWebkitAnimationDirection:
4654                    currValue = parseAnimationDirection();
4655                    if (currValue)
4656                        m_valueList->next();
4657                    break;
4658                case CSSPropertyWebkitAnimationDuration:
4659                case CSSPropertyTransitionDuration:
4660                case CSSPropertyWebkitTransitionDuration:
4661                    currValue = parseAnimationDuration();
4662                    if (currValue)
4663                        m_valueList->next();
4664                    break;
4665                case CSSPropertyWebkitAnimationFillMode:
4666                    currValue = parseAnimationFillMode();
4667                    if (currValue)
4668                        m_valueList->next();
4669                    break;
4670                case CSSPropertyWebkitAnimationIterationCount:
4671                    currValue = parseAnimationIterationCount();
4672                    if (currValue)
4673                        m_valueList->next();
4674                    break;
4675                case CSSPropertyWebkitAnimationName:
4676                    currValue = parseAnimationName();
4677                    if (currValue)
4678                        m_valueList->next();
4679                    break;
4680                case CSSPropertyWebkitAnimationPlayState:
4681                    currValue = parseAnimationPlayState();
4682                    if (currValue)
4683                        m_valueList->next();
4684                    break;
4685                case CSSPropertyTransitionProperty:
4686                case CSSPropertyWebkitTransitionProperty:
4687                    currValue = parseAnimationProperty(context);
4688                    if (value && !context.animationPropertyKeywordAllowed())
4689                        return false;
4690                    if (currValue)
4691                        m_valueList->next();
4692                    break;
4693                case CSSPropertyWebkitAnimationTimingFunction:
4694                case CSSPropertyTransitionTimingFunction:
4695                case CSSPropertyWebkitTransitionTimingFunction:
4696                    currValue = parseAnimationTimingFunction();
4697                    if (currValue)
4698                        m_valueList->next();
4699                    break;
4700                default:
4701                    ASSERT_NOT_REACHED();
4702                    return false;
4703            }
4704
4705            if (!currValue)
4706                return false;
4707
4708            if (value && !values) {
4709                values = CSSValueList::createCommaSeparated();
4710                values->append(value.release());
4711            }
4712
4713            if (values)
4714                values->append(currValue.release());
4715            else
4716                value = currValue.release();
4717
4718            allowComma = true;
4719        }
4720
4721        // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
4722        // properties.
4723        if (inShorthand())
4724            break;
4725    }
4726
4727    if (values && values->length()) {
4728        result = values.release();
4729        return true;
4730    }
4731    if (value) {
4732        result = value.release();
4733        return true;
4734    }
4735    return false;
4736}
4737
4738#if ENABLE(CSS_GRID_LAYOUT)
4739static inline bool isValidCustomIdent(const CSSParserValue& value)
4740{
4741    return value.unit == CSSPrimitiveValue::CSS_IDENT && value.id != CSSValueSpan && value.id != CSSValueAuto;
4742}
4743
4744// The function parses [ <integer> || <custom-ident> ] in <grid-line> (which can be stand alone or with 'span').
4745bool CSSParser::parseIntegerOrCustomIdentFromGridPosition(RefPtr<CSSPrimitiveValue>& numericValue, RefPtr<CSSPrimitiveValue>& gridLineName)
4746{
4747    CSSParserValue* value = m_valueList->current();
4748    if (validUnit(value, FInteger) && value->fValue) {
4749        numericValue = createPrimitiveNumericValue(value);
4750        value = m_valueList->next();
4751        if (value && isValidCustomIdent(*value)) {
4752            gridLineName = createPrimitiveStringValue(m_valueList->current());
4753            m_valueList->next();
4754        }
4755        return true;
4756    }
4757
4758    if (isValidCustomIdent(*value)) {
4759        gridLineName = createPrimitiveStringValue(m_valueList->current());
4760        value = m_valueList->next();
4761        if (value && validUnit(value, FInteger) && value->fValue) {
4762            numericValue = createPrimitiveNumericValue(value);
4763            m_valueList->next();
4764        }
4765        return true;
4766    }
4767
4768    return false;
4769}
4770
4771PassRefPtr<CSSValue> CSSParser::parseGridPosition()
4772{
4773    CSSParserValue* value = m_valueList->current();
4774    if (value->id == CSSValueAuto) {
4775        m_valueList->next();
4776        return cssValuePool().createIdentifierValue(CSSValueAuto);
4777    }
4778
4779    RefPtr<CSSPrimitiveValue> numericValue;
4780    RefPtr<CSSPrimitiveValue> gridLineName;
4781    bool hasSeenSpanKeyword = false;
4782
4783    if (value->id == CSSValueSpan) {
4784        hasSeenSpanKeyword = true;
4785        if (auto* nextValue = m_valueList->next()) {
4786            if (!isForwardSlashOperator(nextValue) && !parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName))
4787                    return nullptr;
4788        }
4789    } else if (parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName)) {
4790        value = m_valueList->current();
4791        if (value && value->id == CSSValueSpan) {
4792            hasSeenSpanKeyword = true;
4793            m_valueList->next();
4794        }
4795    }
4796
4797    // Check that we have consumed all the value list. For shorthands, the parser will pass
4798    // the whole value list (including the opposite position).
4799    if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current()))
4800        return nullptr;
4801
4802    // If we didn't parse anything, this is not a valid grid position.
4803    if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
4804        return nullptr;
4805
4806    // Negative numbers are not allowed for span (but are for <integer>).
4807    if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
4808        return nullptr;
4809
4810    // For the <custom-ident> case.
4811    if (gridLineName && !numericValue && !hasSeenSpanKeyword)
4812        return cssValuePool().createValue(gridLineName->getStringValue(), CSSPrimitiveValue::CSS_STRING);
4813
4814    RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
4815    if (hasSeenSpanKeyword)
4816        values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
4817    if (numericValue)
4818        values->append(numericValue.release());
4819    if (gridLineName)
4820        values->append(gridLineName.release());
4821    ASSERT(values->length());
4822    return values.release();
4823}
4824
4825static PassRefPtr<CSSValue> gridMissingGridPositionValue(CSSValue* value)
4826{
4827    if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isString())
4828        return value;
4829
4830    return cssValuePool().createIdentifierValue(CSSValueAuto);
4831}
4832
4833bool CSSParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
4834{
4835    ShorthandScope scope(this, shorthandId);
4836    const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
4837    ASSERT(shorthand.length() == 2);
4838
4839    RefPtr<CSSValue> startValue = parseGridPosition();
4840    if (!startValue)
4841        return false;
4842
4843    RefPtr<CSSValue> endValue;
4844    if (m_valueList->current()) {
4845        if (!isForwardSlashOperator(m_valueList->current()))
4846            return false;
4847
4848        if (!m_valueList->next())
4849            return false;
4850
4851        endValue = parseGridPosition();
4852        if (!endValue || m_valueList->current())
4853            return false;
4854    } else
4855        endValue = gridMissingGridPositionValue(startValue.get());
4856
4857    addProperty(shorthand.properties()[0], startValue, important);
4858    addProperty(shorthand.properties()[1], endValue, important);
4859    return true;
4860}
4861
4862bool CSSParser::parseGridTemplateRowsAndAreas(PassRefPtr<CSSValue> templateColumns, bool important)
4863{
4864    // At least template-areas strings must be defined.
4865    if (!m_valueList->current())
4866        return false;
4867
4868    NamedGridAreaMap gridAreaMap;
4869    unsigned rowCount = 0;
4870    unsigned columnCount = 0;
4871    bool trailingIdentWasAdded = false;
4872    RefPtr<CSSValueList> templateRows = CSSValueList::createSpaceSeparated();
4873
4874    do {
4875        // Handle leading <custom-ident>*.
4876        if (m_valueList->current()->unit == CSSParserValue::ValueList) {
4877            if (trailingIdentWasAdded) {
4878                // A row's trailing ident must be concatenated with the next row's leading one.
4879                parseGridLineNames(*m_valueList, *templateRows, static_cast<CSSGridLineNamesValue*>(templateRows->item(templateRows->length() - 1)));
4880            } else
4881                parseGridLineNames(*m_valueList, *templateRows);
4882        }
4883
4884        // Handle a template-area's row.
4885        if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
4886            return false;
4887        ++rowCount;
4888
4889        // Handle template-rows's track-size.
4890        if (m_valueList->current() && m_valueList->current()->unit != CSSParserValue::ValueList && m_valueList->current()->unit != CSSPrimitiveValue::CSS_STRING) {
4891            RefPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
4892            if (!value)
4893                return false;
4894            templateRows->append(value.release());
4895        } else
4896            templateRows->append(cssValuePool().createIdentifierValue(CSSValueAuto));
4897
4898        // This will handle the trailing/leading <custom-ident>* in the grammar.
4899        trailingIdentWasAdded = false;
4900        if (m_valueList->current() && m_valueList->current()->unit == CSSParserValue::ValueList) {
4901            parseGridLineNames(*m_valueList, *templateRows);
4902            trailingIdentWasAdded = true;
4903        }
4904    } while (m_valueList->current());
4905
4906    // [<track-list> /]?
4907    if (templateColumns)
4908        addProperty(CSSPropertyWebkitGridTemplateColumns, templateColumns, important);
4909    else
4910        addProperty(CSSPropertyWebkitGridTemplateColumns, cssValuePool().createIdentifierValue(CSSValueNone), important);
4911
4912    // [<line-names>? <string> [<track-size> <line-names>]? ]+
4913    RefPtr<CSSValue> templateAreas = CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
4914    addProperty(CSSPropertyWebkitGridTemplateAreas, templateAreas.release(), important);
4915    addProperty(CSSPropertyWebkitGridTemplateRows, templateRows.release(), important);
4916
4917    return true;
4918}
4919
4920bool CSSParser::parseGridTemplateShorthand(bool important)
4921{
4922    ShorthandScope scope(this, CSSPropertyWebkitGridTemplate);
4923    ASSERT(shorthandForProperty(CSSPropertyWebkitGridTemplate).length() == 3);
4924
4925    // At least "none" must be defined.
4926    if (!m_valueList->current())
4927        return false;
4928
4929    bool firstValueIsNone = m_valueList->current()->id == CSSValueNone;
4930
4931    // 1- 'none' case.
4932    if (firstValueIsNone && !m_valueList->next()) {
4933        addProperty(CSSPropertyWebkitGridTemplateColumns, cssValuePool().createIdentifierValue(CSSValueNone), important);
4934        addProperty(CSSPropertyWebkitGridTemplateRows, cssValuePool().createIdentifierValue(CSSValueNone), important);
4935        addProperty(CSSPropertyWebkitGridTemplateAreas, cssValuePool().createIdentifierValue(CSSValueNone), important);
4936        return true;
4937    }
4938
4939    unsigned index = 0;
4940    RefPtr<CSSValue> columnsValue = firstValueIsNone ? cssValuePool().createIdentifierValue(CSSValueNone) : parseGridTrackList();
4941
4942    // 2- <grid-template-columns> / <grid-template-columns> syntax.
4943    if (columnsValue) {
4944        if (!(m_valueList->current() && isForwardSlashOperator(m_valueList->current()) && m_valueList->next()))
4945            return false;
4946        index = m_valueList->currentIndex();
4947        if (RefPtr<CSSValue> rowsValue = parseGridTrackList()) {
4948            if (m_valueList->current())
4949                return false;
4950            addProperty(CSSPropertyWebkitGridTemplateColumns, columnsValue.release(), important);
4951            addProperty(CSSPropertyWebkitGridTemplateRows, rowsValue.release(), important);
4952            addProperty(CSSPropertyWebkitGridTemplateAreas, cssValuePool().createIdentifierValue(CSSValueNone), important);
4953            return true;
4954        }
4955    }
4956
4957
4958    // 3- [<track-list> /]? [<line-names>? <string> [<track-size> <line-names>]? ]+ syntax.
4959    // The template-columns <track-list> can't be 'none'.
4960    if (firstValueIsNone)
4961        return false;
4962    // It requires to rewind parsing due to previous syntax failures.
4963    m_valueList->setCurrentIndex(index);
4964    return parseGridTemplateRowsAndAreas(columnsValue, important);
4965}
4966
4967bool CSSParser::parseGridShorthand(bool important)
4968{
4969    ShorthandScope scope(this, CSSPropertyWebkitGrid);
4970    ASSERT(shorthandForProperty(CSSPropertyWebkitGrid).length() == 6);
4971
4972    // 1- <grid-template>
4973    if (parseGridTemplateShorthand(important)) {
4974        // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
4975        // The sub-properties not specified are set to their initial value, as normal for shorthands.
4976        addProperty(CSSPropertyWebkitGridAutoFlow, cssValuePool().createImplicitInitialValue(), important);
4977        addProperty(CSSPropertyWebkitGridAutoColumns, cssValuePool().createImplicitInitialValue(), important);
4978        addProperty(CSSPropertyWebkitGridAutoRows, cssValuePool().createImplicitInitialValue(), important);
4979        return true;
4980    }
4981
4982    // Need to rewind parsing to explore the alternative syntax of this shorthand.
4983    m_valueList->setCurrentIndex(0);
4984
4985    // 2- <grid-auto-flow> [ <grid-auto-columns> [ / <grid-auto-rows> ]? ]
4986    if (!parseValue(CSSPropertyWebkitGridAutoFlow, important))
4987        return false;
4988
4989    RefPtr<CSSValue> autoColumnsValue;
4990    RefPtr<CSSValue> autoRowsValue;
4991
4992    if (m_valueList->current()) {
4993        autoColumnsValue = parseGridTrackSize(*m_valueList);
4994        if (!autoColumnsValue)
4995            return false;
4996        if (m_valueList->current()) {
4997            if (!isForwardSlashOperator(m_valueList->current()) || !m_valueList->next())
4998                return false;
4999            autoRowsValue = parseGridTrackSize(*m_valueList);
5000            if (!autoRowsValue)
5001                return false;
5002        }
5003        if (m_valueList->current())
5004            return false;
5005    } else {
5006        // Other omitted values are set to their initial values.
5007        autoColumnsValue = cssValuePool().createImplicitInitialValue();
5008        autoRowsValue = cssValuePool().createImplicitInitialValue();
5009    }
5010
5011    // if <grid-auto-rows> value is omitted, it is set to the value specified for grid-auto-columns.
5012    if (!autoRowsValue)
5013        autoRowsValue = autoColumnsValue;
5014
5015    addProperty(CSSPropertyWebkitGridAutoColumns, autoColumnsValue.release(), important);
5016    addProperty(CSSPropertyWebkitGridAutoRows, autoRowsValue.release(), important);
5017
5018    // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
5019    // The sub-properties not specified are set to their initial value, as normal for shorthands.
5020    addProperty(CSSPropertyWebkitGridTemplateColumns, cssValuePool().createImplicitInitialValue(), important);
5021    addProperty(CSSPropertyWebkitGridTemplateRows, cssValuePool().createImplicitInitialValue(), important);
5022    addProperty(CSSPropertyWebkitGridTemplateAreas, cssValuePool().createImplicitInitialValue(), important);
5023
5024    return true;
5025}
5026
5027bool CSSParser::parseGridAreaShorthand(bool important)
5028{
5029    ShorthandScope scope(this, CSSPropertyWebkitGridArea);
5030    ASSERT(shorthandForProperty(CSSPropertyWebkitGridArea).length() == 4);
5031
5032    RefPtr<CSSValue> rowStartValue = parseGridPosition();
5033    if (!rowStartValue)
5034        return false;
5035
5036    RefPtr<CSSValue> columnStartValue;
5037    if (!parseSingleGridAreaLonghand(columnStartValue))
5038        return false;
5039
5040    RefPtr<CSSValue> rowEndValue;
5041    if (!parseSingleGridAreaLonghand(rowEndValue))
5042        return false;
5043
5044    RefPtr<CSSValue> columnEndValue;
5045    if (!parseSingleGridAreaLonghand(columnEndValue))
5046        return false;
5047
5048    if (!columnStartValue)
5049        columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
5050
5051    if (!rowEndValue)
5052        rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
5053
5054    if (!columnEndValue)
5055        columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
5056
5057    addProperty(CSSPropertyWebkitGridRowStart, rowStartValue, important);
5058    addProperty(CSSPropertyWebkitGridColumnStart, columnStartValue, important);
5059    addProperty(CSSPropertyWebkitGridRowEnd, rowEndValue, important);
5060    addProperty(CSSPropertyWebkitGridColumnEnd, columnEndValue, important);
5061    return true;
5062}
5063
5064bool CSSParser::parseSingleGridAreaLonghand(RefPtr<CSSValue>& property)
5065{
5066    if (!m_valueList->current())
5067        return true;
5068
5069    if (!isForwardSlashOperator(m_valueList->current()))
5070        return false;
5071
5072    if (!m_valueList->next())
5073        return false;
5074
5075    property = parseGridPosition();
5076    return true;
5077}
5078
5079void CSSParser::parseGridLineNames(CSSParserValueList& inputList, CSSValueList& valueList, CSSGridLineNamesValue* previousNamedAreaTrailingLineNames)
5080{
5081    ASSERT(inputList.current() && inputList.current()->unit == CSSParserValue::ValueList);
5082
5083    CSSParserValueList* identList = inputList.current()->valueList;
5084    if (!identList->size()) {
5085        inputList.next();
5086        return;
5087    }
5088
5089    // Need to ensure the identList is at the heading index, since the parserList might have been rewound.
5090    identList->setCurrentIndex(0);
5091
5092    RefPtr<CSSGridLineNamesValue> lineNames = previousNamedAreaTrailingLineNames ? previousNamedAreaTrailingLineNames : CSSGridLineNamesValue::create();
5093    while (CSSParserValue* identValue = identList->current()) {
5094        ASSERT(identValue->unit == CSSPrimitiveValue::CSS_IDENT);
5095        lineNames->append(createPrimitiveStringValue(identValue));
5096        identList->next();
5097    }
5098    if (!previousNamedAreaTrailingLineNames)
5099        valueList.append(lineNames.release());
5100
5101    inputList.next();
5102}
5103
5104PassRefPtr<CSSValue> CSSParser::parseGridTrackList()
5105{
5106    CSSParserValue* value = m_valueList->current();
5107    if (value->id == CSSValueNone) {
5108        m_valueList->next();
5109        return cssValuePool().createIdentifierValue(CSSValueNone);
5110    }
5111
5112    RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
5113    // Handle leading  <custom-ident>*.
5114    value = m_valueList->current();
5115    if (value && value->unit == CSSParserValue::ValueList)
5116        parseGridLineNames(*m_valueList, *values);
5117
5118    bool seenTrackSizeOrRepeatFunction = false;
5119    while (CSSParserValue* currentValue = m_valueList->current()) {
5120        if (isForwardSlashOperator(currentValue))
5121            break;
5122        if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "repeat(")) {
5123            if (!parseGridTrackRepeatFunction(*values))
5124                return nullptr;
5125        } else {
5126            RefPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
5127            if (!value)
5128                return nullptr;
5129            values->append(value.release());
5130        }
5131        seenTrackSizeOrRepeatFunction = true;
5132
5133        // This will handle the trailing <custom-ident>* in the grammar.
5134        value = m_valueList->current();
5135        if (value && value->unit == CSSParserValue::ValueList)
5136            parseGridLineNames(*m_valueList, *values);
5137    }
5138
5139    if (!seenTrackSizeOrRepeatFunction)
5140        return nullptr;
5141
5142    return values.release();
5143}
5144
5145bool CSSParser::parseGridTrackRepeatFunction(CSSValueList& list)
5146{
5147    CSSParserValueList* arguments = m_valueList->current()->function->args.get();
5148    if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1)))
5149        return false;
5150
5151    ASSERT_WITH_SECURITY_IMPLICATION(arguments->valueAt(0)->fValue > 0);
5152    size_t repetitions = arguments->valueAt(0)->fValue;
5153    // Clamp repetitions at MAX_GRID_TRACK_REPETITIONS.
5154    // http://www.w3.org/TR/css-grid-1/#repeat-notation
5155    if (repetitions > MAX_GRID_TRACK_REPETITIONS)
5156        repetitions = MAX_GRID_TRACK_REPETITIONS;
5157    RefPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
5158    arguments->next(); // Skip the repetition count.
5159    arguments->next(); // Skip the comma.
5160
5161    // Handle leading <custom-ident>*.
5162    CSSParserValue* currentValue = arguments->current();
5163    if (currentValue && currentValue->unit == CSSParserValue::ValueList)
5164        parseGridLineNames(*arguments, *repeatedValues);
5165
5166    while (arguments->current()) {
5167        RefPtr<CSSValue> trackSize = parseGridTrackSize(*arguments);
5168        if (!trackSize)
5169            return false;
5170
5171        repeatedValues->append(trackSize.release());
5172
5173        // This takes care of any trailing <custom-ident>* in the grammar.
5174        currentValue = arguments->current();
5175        if (currentValue && currentValue->unit == CSSParserValue::ValueList)
5176            parseGridLineNames(*arguments, *repeatedValues);
5177    }
5178
5179    for (size_t i = 0; i < repetitions; ++i) {
5180        for (size_t j = 0; j < repeatedValues->length(); ++j)
5181            list.append(repeatedValues->itemWithoutBoundsCheck(j));
5182    }
5183
5184    m_valueList->next();
5185    return true;
5186}
5187
5188PassRefPtr<CSSValue> CSSParser::parseGridTrackSize(CSSParserValueList& inputList)
5189{
5190    CSSParserValue* currentValue = inputList.current();
5191    inputList.next();
5192
5193    if (currentValue->id == CSSValueAuto)
5194        return cssValuePool().createIdentifierValue(CSSValueAuto);
5195
5196    if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax(")) {
5197        // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
5198        CSSParserValueList* arguments = currentValue->function->args.get();
5199        if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
5200            return 0;
5201
5202        RefPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0));
5203        if (!minTrackBreadth)
5204            return 0;
5205
5206        RefPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2));
5207        if (!maxTrackBreadth)
5208            return 0;
5209
5210        RefPtr<CSSValueList> parsedArguments = CSSValueList::createCommaSeparated();
5211        parsedArguments->append(minTrackBreadth);
5212        parsedArguments->append(maxTrackBreadth);
5213        return CSSFunctionValue::create("minmax(", parsedArguments);
5214    }
5215
5216    return parseGridBreadth(currentValue);
5217}
5218
5219PassRefPtr<CSSPrimitiveValue> CSSParser::parseGridBreadth(CSSParserValue* currentValue)
5220{
5221    if (currentValue->id == CSSValueWebkitMinContent || currentValue->id == CSSValueWebkitMaxContent)
5222        return cssValuePool().createIdentifierValue(currentValue->id);
5223
5224    if (currentValue->unit == CSSPrimitiveValue::CSS_FR) {
5225        double flexValue = currentValue->fValue;
5226
5227        // Fractional unit is a non-negative dimension.
5228        if (flexValue <= 0)
5229            return 0;
5230
5231        return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR);
5232    }
5233
5234    if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
5235        return 0;
5236
5237    return createPrimitiveNumericValue(currentValue);
5238}
5239
5240static inline bool isValidGridAutoFlowId(CSSValueID id)
5241{
5242    return (id == CSSValueRow || id == CSSValueColumn || id == CSSValueDense || id == CSSValueStack);
5243}
5244
5245PassRefPtr<CSSValue> CSSParser::parseGridAutoFlow(CSSParserValueList& inputList)
5246{
5247    // [ row | column ] && dense? | stack && [ row | column ]?
5248    CSSParserValue* value = inputList.current();
5249    if (!value)
5250        return nullptr;
5251
5252    RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
5253
5254    // First parameter.
5255    CSSValueID firstId = value->id;
5256    if (!isValidGridAutoFlowId(firstId))
5257        return nullptr;
5258
5259    // Second parameter, if any.
5260    // If second parameter is not valid we should process anyway the first one as we can be inside the "grid" shorthand.
5261    value = inputList.next();
5262    if (!value || !isValidGridAutoFlowId(value->id)) {
5263        if (firstId == CSSValueDense)
5264            return nullptr;
5265
5266        if (firstId == CSSValueStack)
5267            parsedValues->append(cssValuePool().createIdentifierValue(CSSValueRow));
5268
5269        parsedValues->append(cssValuePool().createIdentifierValue(firstId));
5270        return parsedValues;
5271    }
5272
5273    switch (firstId) {
5274    case CSSValueRow:
5275    case CSSValueColumn:
5276        parsedValues->append(cssValuePool().createIdentifierValue(firstId));
5277        if (value->id == CSSValueDense || value->id == CSSValueStack) {
5278            parsedValues->append(cssValuePool().createIdentifierValue(value->id));
5279            inputList.next();
5280        }
5281        break;
5282    case CSSValueDense:
5283    case CSSValueStack:
5284        if (value->id == CSSValueRow || value->id == CSSValueColumn) {
5285            parsedValues->append(cssValuePool().createIdentifierValue(value->id));
5286            inputList.next();
5287        }
5288        parsedValues->append(cssValuePool().createIdentifierValue(firstId));
5289        break;
5290    default:
5291        ASSERT_NOT_REACHED();
5292        break;
5293    }
5294
5295    return parsedValues;
5296}
5297#endif /* ENABLE(CSS_GRID_LAYOUT) */
5298
5299#if ENABLE(DASHBOARD_SUPPORT)
5300
5301#define DASHBOARD_REGION_NUM_PARAMETERS  6
5302#define DASHBOARD_REGION_SHORT_NUM_PARAMETERS  2
5303
5304static CSSParserValue* skipCommaInDashboardRegion(CSSParserValueList *args)
5305{
5306    if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) ||
5307         args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
5308        CSSParserValue* current = args->current();
5309        if (current->unit == CSSParserValue::Operator && current->iValue == ',')
5310            return args->next();
5311    }
5312    return args->current();
5313}
5314
5315bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important)
5316{
5317    bool valid = true;
5318
5319    CSSParserValue* value = m_valueList->current();
5320
5321    if (value->id == CSSValueNone) {
5322        if (m_valueList->next())
5323            return false;
5324        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
5325        return valid;
5326    }
5327
5328    RefPtr<DashboardRegion> firstRegion = DashboardRegion::create();
5329    DashboardRegion* region = 0;
5330
5331    while (value) {
5332        if (region == 0) {
5333            region = firstRegion.get();
5334        } else {
5335            RefPtr<DashboardRegion> nextRegion = DashboardRegion::create();
5336            region->m_next = nextRegion;
5337            region = nextRegion.get();
5338        }
5339
5340        if (value->unit != CSSParserValue::Function) {
5341            valid = false;
5342            break;
5343        }
5344
5345        // Commas count as values, so allow (function name is dashboard-region for DASHBOARD_SUPPORT feature):
5346        // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
5347        // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
5348        // also allow
5349        // dashboard-region(label, type) or dashboard-region(label type)
5350        // dashboard-region(label, type) or dashboard-region(label type)
5351        CSSParserValueList* args = value->function->args.get();
5352        if (!equalIgnoringCase(value->function->name, "dashboard-region(") || !args) {
5353            valid = false;
5354            break;
5355        }
5356
5357        int numArgs = args->size();
5358        if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) &&
5359            (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))) {
5360            valid = false;
5361            break;
5362        }
5363
5364        // First arg is a label.
5365        CSSParserValue* arg = args->current();
5366        if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
5367            valid = false;
5368            break;
5369        }
5370
5371        region->m_label = arg->string;
5372
5373        // Second arg is a type.
5374        arg = args->next();
5375        arg = skipCommaInDashboardRegion(args);
5376        if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
5377            valid = false;
5378            break;
5379        }
5380
5381        if (equalIgnoringCase(arg, "circle"))
5382            region->m_isCircle = true;
5383        else if (equalIgnoringCase(arg, "rectangle"))
5384            region->m_isRectangle = true;
5385        else {
5386            valid = false;
5387            break;
5388        }
5389
5390        region->m_geometryType = arg->string;
5391
5392        if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
5393            // This originally used CSSValueInvalid by accident. It might be more logical to use something else.
5394            RefPtr<CSSPrimitiveValue> amount = cssValuePool().createIdentifierValue(CSSValueInvalid);
5395
5396            region->setTop(amount);
5397            region->setRight(amount);
5398            region->setBottom(amount);
5399            region->setLeft(amount);
5400        } else {
5401            // Next four arguments must be offset numbers
5402            int i;
5403            for (i = 0; i < 4; i++) {
5404                arg = args->next();
5405                arg = skipCommaInDashboardRegion(args);
5406
5407                valid = arg->id == CSSValueAuto || validUnit(arg, FLength);
5408                if (!valid)
5409                    break;
5410
5411                RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ?
5412                    cssValuePool().createIdentifierValue(CSSValueAuto) :
5413                    createPrimitiveNumericValue(arg);
5414
5415                if (i == 0)
5416                    region->setTop(amount);
5417                else if (i == 1)
5418                    region->setRight(amount);
5419                else if (i == 2)
5420                    region->setBottom(amount);
5421                else
5422                    region->setLeft(amount);
5423            }
5424        }
5425
5426        if (args->next())
5427            return false;
5428
5429        value = m_valueList->next();
5430    }
5431
5432    if (valid)
5433        addProperty(propId, cssValuePool().createValue(firstRegion.release()), important);
5434
5435    return valid;
5436}
5437
5438#endif /* ENABLE(DASHBOARD_SUPPORT) */
5439
5440#if ENABLE(CSS_GRID_LAYOUT)
5441bool CSSParser::parseGridTemplateAreasRow(NamedGridAreaMap& gridAreaMap, const unsigned rowCount, unsigned& columnCount)
5442{
5443    CSSParserValue* currentValue = m_valueList->current();
5444    if (!currentValue || currentValue->unit != CSSPrimitiveValue::CSS_STRING)
5445        return false;
5446
5447    String gridRowNames = currentValue->string;
5448    if (gridRowNames.isEmpty())
5449        return false;
5450
5451    Vector<String> columnNames;
5452    gridRowNames.split(' ', columnNames);
5453
5454    if (!columnCount) {
5455        columnCount = columnNames.size();
5456        ASSERT(columnCount);
5457    } else if (columnCount != columnNames.size()) {
5458        // The declaration is invalid is all the rows don't have the number of columns.
5459        return false;
5460    }
5461
5462    for (unsigned currentColumn = 0; currentColumn < columnCount; ++currentColumn) {
5463        const String& gridAreaName = columnNames[currentColumn];
5464
5465        // Unamed areas are always valid (we consider them to be 1x1).
5466        if (gridAreaName == ".")
5467            continue;
5468
5469        // We handle several grid areas with the same name at once to simplify the validation code.
5470        unsigned lookAheadColumn;
5471        for (lookAheadColumn = currentColumn; lookAheadColumn < columnCount - 1; ++lookAheadColumn) {
5472            if (columnNames[lookAheadColumn + 1] != gridAreaName)
5473                break;
5474        }
5475
5476        auto gridAreaIterator = gridAreaMap.find(gridAreaName);
5477        if (gridAreaIterator == gridAreaMap.end())
5478            gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowCount), GridSpan(currentColumn, lookAheadColumn)));
5479        else {
5480            GridCoordinate& gridCoordinate = gridAreaIterator->value;
5481
5482            // The following checks test that the grid area is a single filled-in rectangle.
5483            // 1. The new row is adjacent to the previously parsed row.
5484            if (rowCount != gridCoordinate.rows.resolvedFinalPosition.next().toInt())
5485                return 0;
5486
5487            // 2. The new area starts at the same position as the previously parsed area.
5488            if (currentColumn != gridCoordinate.columns.resolvedInitialPosition.toInt())
5489                return 0;
5490
5491            // 3. The new area ends at the same position as the previously parsed area.
5492            if (lookAheadColumn != gridCoordinate.columns.resolvedFinalPosition.toInt())
5493                return 0;
5494
5495            ++gridCoordinate.rows.resolvedFinalPosition;
5496        }
5497        currentColumn = lookAheadColumn;
5498    }
5499
5500    m_valueList->next();
5501    return true;
5502}
5503
5504PassRefPtr<CSSValue> CSSParser::parseGridTemplateAreas()
5505{
5506    NamedGridAreaMap gridAreaMap;
5507    unsigned rowCount = 0;
5508    unsigned columnCount = 0;
5509
5510    while (m_valueList->current()) {
5511        if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
5512            return 0;
5513        ++rowCount;
5514    }
5515
5516    if (!rowCount || !columnCount)
5517        return 0;
5518
5519    return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
5520}
5521#endif /* ENABLE(CSS_GRID_LAYOUT) */
5522
5523PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
5524{
5525    unsigned numArgs = args->size();
5526    if (counters && numArgs != 3 && numArgs != 5)
5527        return 0;
5528    if (!counters && numArgs != 1 && numArgs != 3)
5529        return 0;
5530
5531    CSSParserValue* i = args->current();
5532    if (i->unit != CSSPrimitiveValue::CSS_IDENT)
5533        return 0;
5534    RefPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i);
5535
5536    RefPtr<CSSPrimitiveValue> separator;
5537    if (!counters)
5538        separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING);
5539    else {
5540        i = args->next();
5541        if (i->unit != CSSParserValue::Operator || i->iValue != ',')
5542            return 0;
5543
5544        i = args->next();
5545        if (i->unit != CSSPrimitiveValue::CSS_STRING)
5546            return 0;
5547
5548        separator = createPrimitiveStringValue(i);
5549    }
5550
5551    RefPtr<CSSPrimitiveValue> listStyle;
5552    i = args->next();
5553    if (!i) // Make the list style default decimal
5554        listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
5555    else {
5556        if (i->unit != CSSParserValue::Operator || i->iValue != ',')
5557            return 0;
5558
5559        i = args->next();
5560        if (i->unit != CSSPrimitiveValue::CSS_IDENT)
5561            return 0;
5562
5563        CSSValueID listStyleID = CSSValueInvalid;
5564        if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha))
5565            listStyleID = i->id;
5566        else
5567            return 0;
5568
5569        listStyle = cssValuePool().createIdentifierValue(listStyleID);
5570    }
5571
5572    return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
5573}
5574
5575bool CSSParser::parseClipShape(CSSPropertyID propId, bool important)
5576{
5577    CSSParserValue* value = m_valueList->current();
5578    CSSParserValueList* args = value->function->args.get();
5579
5580    if (!equalIgnoringCase(value->function->name, "rect(") || !args)
5581        return false;
5582
5583    // rect(t, r, b, l) || rect(t r b l)
5584    if (args->size() != 4 && args->size() != 7)
5585        return false;
5586    RefPtr<Rect> rect = Rect::create();
5587    bool valid = true;
5588    int i = 0;
5589    CSSParserValue* a = args->current();
5590    while (a) {
5591        valid = a->id == CSSValueAuto || validUnit(a, FLength);
5592        if (!valid)
5593            break;
5594        RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
5595            cssValuePool().createIdentifierValue(CSSValueAuto) :
5596            createPrimitiveNumericValue(a);
5597        if (i == 0)
5598            rect->setTop(length);
5599        else if (i == 1)
5600            rect->setRight(length);
5601        else if (i == 2)
5602            rect->setBottom(length);
5603        else
5604            rect->setLeft(length);
5605        a = args->next();
5606        if (a && args->size() == 7) {
5607            if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
5608                a = args->next();
5609            } else {
5610                valid = false;
5611                break;
5612            }
5613        }
5614        i++;
5615    }
5616    if (valid) {
5617        addProperty(propId, cssValuePool().createValue(rect.release()), important);
5618        m_valueList->next();
5619        return true;
5620    }
5621    return false;
5622}
5623
5624static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4])
5625{
5626    if (radii[3])
5627        return;
5628    if (!radii[2]) {
5629        if (!radii[1])
5630            radii[1] = radii[0];
5631        radii[2] = radii[0];
5632    }
5633    radii[3] = radii[1];
5634}
5635
5636// FIXME: This should be refactored with CSSParser::parseBorderRadius.
5637// CSSParser::parseBorderRadius contains support for some legacy radius construction.
5638PassRefPtr<CSSBasicShape> CSSParser::parseInsetRoundedCorners(PassRefPtr<CSSBasicShapeInset> shape, CSSParserValueList* args)
5639{
5640    CSSParserValue* argument = args->next();
5641
5642    if (!argument)
5643        return nullptr;
5644
5645    Vector<CSSParserValue*> radiusArguments;
5646    while (argument) {
5647        radiusArguments.append(argument);
5648        argument = args->next();
5649    }
5650
5651    unsigned num = radiusArguments.size();
5652    if (!num || num > 9)
5653        return nullptr;
5654
5655    RefPtr<CSSPrimitiveValue> radii[2][4];
5656
5657    unsigned indexAfterSlash = 0;
5658    for (unsigned i = 0; i < num; ++i) {
5659        CSSParserValue* value = radiusArguments.at(i);
5660        if (value->unit == CSSParserValue::Operator) {
5661            if (value->iValue != '/')
5662                return nullptr;
5663
5664            if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
5665                return nullptr;
5666
5667            indexAfterSlash = i + 1;
5668            completeBorderRadii(radii[0]);
5669            continue;
5670        }
5671
5672        if (i - indexAfterSlash >= 4)
5673            return nullptr;
5674
5675        if (!validUnit(value, FLength | FPercent | FNonNeg))
5676            return nullptr;
5677
5678        RefPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
5679
5680        if (!indexAfterSlash)
5681            radii[0][i] = radius;
5682        else
5683            radii[1][i - indexAfterSlash] = radius.release();
5684    }
5685
5686    if (!indexAfterSlash) {
5687        completeBorderRadii(radii[0]);
5688        for (unsigned i = 0; i < 4; ++i)
5689            radii[1][i] = radii[0][i];
5690    } else
5691        completeBorderRadii(radii[1]);
5692
5693    shape->setTopLeftRadius(createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()));
5694    shape->setTopRightRadius(createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()));
5695    shape->setBottomRightRadius(createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()));
5696    shape->setBottomLeftRadius(createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()));
5697
5698    return shape;
5699}
5700
5701PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeInset(CSSParserValueList* args)
5702{
5703    ASSERT(args);
5704
5705    RefPtr<CSSBasicShapeInset> shape = CSSBasicShapeInset::create();
5706
5707    CSSParserValue* argument = args->current();
5708    Vector<RefPtr<CSSPrimitiveValue> > widthArguments;
5709    bool hasRoundedInset = false;
5710    while (argument) {
5711        if (argument->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(argument->string, "round")) {
5712            hasRoundedInset = true;
5713            break;
5714        }
5715
5716        Units unitFlags = FLength | FPercent;
5717        if (!validUnit(argument, unitFlags) || widthArguments.size() > 4)
5718            return nullptr;
5719
5720        widthArguments.append(createPrimitiveNumericValue(argument));
5721        argument = args->next();
5722    }
5723
5724    switch (widthArguments.size()) {
5725    case 1: {
5726        shape->updateShapeSize1Value(widthArguments[0].get());
5727        break;
5728    }
5729    case 2: {
5730        shape->updateShapeSize2Values(widthArguments[0].get(), widthArguments[1].get());
5731        break;
5732        }
5733    case 3: {
5734        shape->updateShapeSize3Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get());
5735        break;
5736    }
5737    case 4: {
5738        shape->updateShapeSize4Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get(), widthArguments[3].get());
5739        break;
5740    }
5741    default:
5742        return nullptr;
5743    }
5744
5745    if (hasRoundedInset)
5746        return parseInsetRoundedCorners(shape, args);
5747    return shape;
5748}
5749
5750PassRefPtr<CSSPrimitiveValue> CSSParser::parseShapeRadius(CSSParserValue* value)
5751{
5752    if (value->id == CSSValueClosestSide || value->id == CSSValueFarthestSide)
5753        return cssValuePool().createIdentifierValue(value->id);
5754
5755    if (!validUnit(value, FLength | FPercent | FNonNeg))
5756        return 0;
5757
5758    return createPrimitiveNumericValue(value);
5759}
5760
5761PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeCircle(CSSParserValueList* args)
5762{
5763    ASSERT(args);
5764
5765    // circle(radius)
5766    // circle(radius at <position>)
5767    // circle(at <position>)
5768    // where position defines centerX and centerY using a CSS <position> data type.
5769    RefPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
5770
5771    for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
5772        // The call to parseFillPosition below should consume all of the
5773        // arguments except the first two. Thus, and index greater than one
5774        // indicates an invalid production.
5775        if (args->currentIndex() > 1)
5776            return 0;
5777
5778        if (!args->currentIndex() && argument->id != CSSValueAt) {
5779            if (RefPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
5780                shape->setRadius(radius);
5781                continue;
5782            }
5783
5784            return 0;
5785        }
5786
5787        if (argument->id == CSSValueAt && args->next()) {
5788            RefPtr<CSSValue> centerX;
5789            RefPtr<CSSValue> centerY;
5790            parseFillPosition(args, centerX, centerY);
5791            if (centerX && centerY && !args->current()) {
5792                ASSERT(centerX->isPrimitiveValue());
5793                ASSERT(centerY->isPrimitiveValue());
5794                shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
5795                shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
5796            } else
5797                return 0;
5798        } else
5799            return 0;
5800    }
5801
5802    return shape;
5803}
5804
5805PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeEllipse(CSSParserValueList* args)
5806{
5807    ASSERT(args);
5808
5809    // ellipse(radiusX)
5810    // ellipse(radiusX at <position>)
5811    // ellipse(radiusX radiusY)
5812    // ellipse(radiusX radiusY at <position>)
5813    // ellipse(at <position>)
5814    // where position defines centerX and centerY using a CSS <position> data type.
5815    RefPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
5816
5817    for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
5818        // The call to parseFillPosition below should consume all of the
5819        // arguments except the first three. Thus, an index greater than two
5820        // indicates an invalid production.
5821        if (args->currentIndex() > 2)
5822            return 0;
5823
5824        if (args->currentIndex() < 2 && argument->id != CSSValueAt) {
5825            if (RefPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
5826                if (!shape->radiusX())
5827                    shape->setRadiusX(radius);
5828                else
5829                    shape->setRadiusY(radius);
5830                continue;
5831            }
5832
5833            return 0;
5834        }
5835
5836        if (argument->id != CSSValueAt || !args->next()) // expecting ellipse(.. at <position>)
5837            return 0;
5838
5839        RefPtr<CSSValue> centerX;
5840        RefPtr<CSSValue> centerY;
5841        parseFillPosition(args, centerX, centerY);
5842        if (!centerX || !centerY || args->current())
5843            return 0;
5844
5845        ASSERT(centerX->isPrimitiveValue());
5846        ASSERT(centerY->isPrimitiveValue());
5847        shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
5848        shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
5849    }
5850
5851    return shape;
5852}
5853
5854PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapePolygon(CSSParserValueList* args)
5855{
5856    ASSERT(args);
5857
5858    unsigned size = args->size();
5859    if (!size)
5860        return 0;
5861
5862    RefPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
5863
5864    CSSParserValue* argument = args->current();
5865    if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
5866        shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
5867
5868        if (!isComma(args->next()))
5869            return 0;
5870
5871        argument = args->next();
5872        size -= 2;
5873    }
5874
5875    // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one
5876    if (!size || (size % 3) - 2)
5877        return 0;
5878
5879    CSSParserValue* argumentX = argument;
5880    while (argumentX) {
5881
5882        if (!validUnit(argumentX, FLength | FPercent))
5883            return 0;
5884        RefPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX);
5885
5886        CSSParserValue* argumentY = args->next();
5887        if (!argumentY || !validUnit(argumentY, FLength | FPercent))
5888            return 0;
5889        RefPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY);
5890
5891        shape->appendPoint(xLength.release(), yLength.release());
5892
5893        CSSParserValue* commaOrNull = args->next();
5894        if (!commaOrNull)
5895            argumentX = 0;
5896        else if (!isComma(commaOrNull))
5897            return 0;
5898        else
5899            argumentX = args->next();
5900    }
5901
5902    return shape;
5903}
5904
5905static bool isBoxValue(CSSValueID valueId, CSSPropertyID propId)
5906{
5907    switch (valueId) {
5908    case CSSValueContentBox:
5909    case CSSValuePaddingBox:
5910    case CSSValueBorderBox:
5911    case CSSValueMarginBox:
5912        return true;
5913    case CSSValueFill:
5914    case CSSValueStroke:
5915    case CSSValueViewBox:
5916        return propId == CSSPropertyWebkitClipPath;
5917    default: break;
5918    }
5919
5920    return false;
5921}
5922
5923PassRefPtr<CSSValue> CSSParser::parseBasicShapeAndOrBox(CSSPropertyID propId)
5924{
5925    CSSParserValue* value = m_valueList->current();
5926
5927    bool shapeFound = false;
5928    bool boxFound = false;
5929    CSSValueID valueId;
5930
5931    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
5932    for (unsigned i = 0; i < 2; ++i) {
5933        if (!value)
5934            break;
5935        valueId = value->id;
5936        if (value->unit == CSSParserValue::Function && !shapeFound) {
5937            // parseBasicShape already asks for the next value list item.
5938            RefPtr<CSSPrimitiveValue> shapeValue = parseBasicShape();
5939            if (!shapeValue)
5940                return nullptr;
5941            list->append(shapeValue.release());
5942            shapeFound = true;
5943        } else if (isBoxValue(valueId, propId) && !boxFound) {
5944            list->append(parseValidPrimitive(valueId, value));
5945            boxFound = true;
5946            m_valueList->next();
5947        } else
5948            return nullptr;
5949        value = m_valueList->current();
5950    }
5951
5952    if (m_valueList->current())
5953        return nullptr;
5954    return list.release();
5955}
5956
5957#if ENABLE(CSS_SHAPES)
5958PassRefPtr<CSSValue> CSSParser::parseShapeProperty(CSSPropertyID propId)
5959{
5960    if (!RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled())
5961        return nullptr;
5962
5963    CSSParserValue* value = m_valueList->current();
5964    CSSValueID valueId = value->id;
5965    RefPtr<CSSPrimitiveValue> keywordValue;
5966    RefPtr<CSSPrimitiveValue> shapeValue;
5967
5968    if (valueId == CSSValueNone) {
5969        keywordValue = parseValidPrimitive(valueId, value);
5970        m_valueList->next();
5971        return keywordValue.release();
5972    }
5973
5974    RefPtr<CSSValue> imageValue;
5975    if (valueId != CSSValueNone && parseFillImage(m_valueList.get(), imageValue)) {
5976        m_valueList->next();
5977        return imageValue.release();
5978    }
5979
5980    return parseBasicShapeAndOrBox(propId);
5981}
5982#endif
5983
5984PassRefPtr<CSSValue> CSSParser::parseClipPath()
5985{
5986    CSSParserValue* value = m_valueList->current();
5987    CSSValueID valueId = value->id;
5988
5989    if (valueId == CSSValueNone) {
5990        m_valueList->next();
5991        return parseValidPrimitive(valueId, value);
5992    }
5993    if (value->unit == CSSPrimitiveValue::CSS_URI) {
5994        m_valueList->next();
5995        return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
5996    }
5997
5998    return parseBasicShapeAndOrBox(CSSPropertyWebkitClipPath);
5999}
6000
6001PassRefPtr<CSSPrimitiveValue> CSSParser::parseBasicShape()
6002{
6003    CSSParserValue* value = m_valueList->current();
6004    ASSERT(value->unit == CSSParserValue::Function);
6005    CSSParserValueList* args = value->function->args.get();
6006
6007    if (!args)
6008        return nullptr;
6009
6010    RefPtr<CSSBasicShape> shape;
6011    if (equalIgnoringCase(value->function->name, "circle("))
6012        shape = parseBasicShapeCircle(args);
6013    else if (equalIgnoringCase(value->function->name, "ellipse("))
6014        shape = parseBasicShapeEllipse(args);
6015    else if (equalIgnoringCase(value->function->name, "polygon("))
6016        shape = parseBasicShapePolygon(args);
6017    else if (equalIgnoringCase(value->function->name, "inset("))
6018        shape = parseBasicShapeInset(args);
6019
6020    if (!shape)
6021        return nullptr;
6022
6023    m_valueList->next();
6024    return cssValuePool().createValue(shape.release());
6025}
6026
6027// [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
6028bool CSSParser::parseFont(bool important)
6029{
6030    // Let's check if there is an inherit or initial somewhere in the shorthand.
6031    for (unsigned i = 0; i < m_valueList->size(); ++i) {
6032        if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial)
6033            return false;
6034    }
6035
6036    ShorthandScope scope(this, CSSPropertyFont);
6037    // Optional font-style, font-variant and font-weight.
6038    bool fontStyleParsed = false;
6039    bool fontVariantParsed = false;
6040    bool fontWeightParsed = false;
6041    CSSParserValue* value;
6042    while ((value = m_valueList->current())) {
6043        if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
6044            addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
6045            fontStyleParsed = true;
6046        } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
6047            // Font variant in the shorthand is particular, it only accepts normal or small-caps.
6048            addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important);
6049            fontVariantParsed = true;
6050        } else if (!fontWeightParsed && parseFontWeight(important))
6051            fontWeightParsed = true;
6052        else
6053            break;
6054        m_valueList->next();
6055    }
6056
6057    if (!value)
6058        return false;
6059
6060    if (!fontStyleParsed)
6061        addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
6062    if (!fontVariantParsed)
6063        addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
6064    if (!fontWeightParsed)
6065        addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
6066
6067    // Now a font size _must_ come.
6068    // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
6069    if (!parseFontSize(important))
6070        return false;
6071
6072    value = m_valueList->current();
6073    if (!value)
6074        return false;
6075
6076    if (isForwardSlashOperator(value)) {
6077        // The line-height property.
6078        value = m_valueList->next();
6079        if (!value)
6080            return false;
6081        if (!parseLineHeight(important))
6082            return false;
6083    } else
6084        addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
6085
6086    // Font family must come now.
6087    RefPtr<CSSValue> parsedFamilyValue = parseFontFamily();
6088    if (!parsedFamilyValue)
6089        return false;
6090
6091    addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
6092
6093    // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
6094    // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
6095    // but we don't seem to support them at the moment. They should also be added here once implemented.
6096    if (m_valueList->current())
6097        return false;
6098
6099    return true;
6100}
6101
6102class FontFamilyValueBuilder {
6103public:
6104    FontFamilyValueBuilder(CSSValueList* list)
6105        : m_list(list)
6106    {
6107    }
6108
6109    void add(const CSSParserString& string)
6110    {
6111        if (!m_builder.isEmpty())
6112            m_builder.append(' ');
6113
6114        if (string.is8Bit()) {
6115            m_builder.append(string.characters8(), string.length());
6116            return;
6117        }
6118
6119        m_builder.append(string.characters16(), string.length());
6120    }
6121
6122    void commit()
6123    {
6124        if (m_builder.isEmpty())
6125            return;
6126        m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString()));
6127        m_builder.clear();
6128    }
6129
6130private:
6131    StringBuilder m_builder;
6132    CSSValueList* m_list;
6133};
6134
6135PassRefPtr<CSSValueList> CSSParser::parseFontFamily()
6136{
6137    RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
6138    CSSParserValue* value = m_valueList->current();
6139
6140    FontFamilyValueBuilder familyBuilder(list.get());
6141    bool inFamily = false;
6142
6143    while (value) {
6144        CSSParserValue* nextValue = m_valueList->next();
6145        bool nextValBreaksFont = !nextValue ||
6146                                 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
6147        bool nextValIsFontName = nextValue &&
6148            ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
6149            (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
6150
6151        bool valueIsKeyword = value->id == CSSValueInitial || value->id == CSSValueInherit || value->id == CSSValueDefault;
6152        if (valueIsKeyword && !inFamily) {
6153            if (nextValBreaksFont)
6154                value = m_valueList->next();
6155            else if (nextValIsFontName)
6156                value = nextValue;
6157            continue;
6158        }
6159
6160        if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
6161            if (inFamily)
6162                familyBuilder.add(value->string);
6163            else if (nextValBreaksFont || !nextValIsFontName)
6164                list->append(cssValuePool().createIdentifierValue(value->id));
6165            else {
6166                familyBuilder.commit();
6167                familyBuilder.add(value->string);
6168                inFamily = true;
6169            }
6170        } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
6171            // Strings never share in a family name.
6172            inFamily = false;
6173            familyBuilder.commit();
6174            list->append(cssValuePool().createFontFamilyValue(value->string));
6175        } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
6176            if (inFamily)
6177                familyBuilder.add(value->string);
6178            else if (nextValBreaksFont || !nextValIsFontName)
6179                list->append(cssValuePool().createFontFamilyValue(value->string));
6180            else {
6181                familyBuilder.commit();
6182                familyBuilder.add(value->string);
6183                inFamily = true;
6184            }
6185        } else {
6186            break;
6187        }
6188
6189        if (!nextValue)
6190            break;
6191
6192        if (nextValBreaksFont) {
6193            value = m_valueList->next();
6194            familyBuilder.commit();
6195            inFamily = false;
6196        }
6197        else if (nextValIsFontName)
6198            value = nextValue;
6199        else
6200            break;
6201    }
6202    familyBuilder.commit();
6203
6204    if (!list->length())
6205        list = 0;
6206    return list.release();
6207}
6208
6209bool CSSParser::parseLineHeight(bool important)
6210{
6211    CSSParserValue* value = m_valueList->current();
6212    CSSValueID id = value->id;
6213    bool validPrimitive = false;
6214    // normal | <number> | <length> | <percentage> | inherit
6215    if (id == CSSValueNormal)
6216        validPrimitive = true;
6217    else
6218        validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
6219    if (validPrimitive && (!m_valueList->next() || inShorthand()))
6220        addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important);
6221    return validPrimitive;
6222}
6223
6224bool CSSParser::parseFontSize(bool important)
6225{
6226    CSSParserValue* value = m_valueList->current();
6227    CSSValueID id = value->id;
6228    bool validPrimitive = false;
6229    // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
6230    if (id >= CSSValueXxSmall && id <= CSSValueLarger)
6231        validPrimitive = true;
6232    else
6233        validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
6234    if (validPrimitive && (!m_valueList->next() || inShorthand()))
6235        addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important);
6236    return validPrimitive;
6237}
6238
6239bool CSSParser::parseFontVariant(bool important)
6240{
6241    RefPtr<CSSValueList> values;
6242    if (m_valueList->size() > 1)
6243        values = CSSValueList::createCommaSeparated();
6244    CSSParserValue* val;
6245    bool expectComma = false;
6246    while ((val = m_valueList->current())) {
6247        RefPtr<CSSPrimitiveValue> parsedValue;
6248        if (!expectComma) {
6249            expectComma = true;
6250            if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
6251                parsedValue = cssValuePool().createIdentifierValue(val->id);
6252            else if (val->id == CSSValueAll && !values) {
6253                // 'all' is only allowed in @font-face and with no other values. Make a value list to
6254                // indicate that we are in the @font-face case.
6255                values = CSSValueList::createCommaSeparated();
6256                parsedValue = cssValuePool().createIdentifierValue(val->id);
6257            }
6258        } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
6259            expectComma = false;
6260            m_valueList->next();
6261            continue;
6262        }
6263
6264        if (!parsedValue)
6265            return false;
6266
6267        m_valueList->next();
6268
6269        if (values)
6270            values->append(parsedValue.release());
6271        else {
6272            addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
6273            return true;
6274        }
6275    }
6276
6277    if (values && values->length()) {
6278        m_hasFontFaceOnlyValues = true;
6279        addProperty(CSSPropertyFontVariant, values.release(), important);
6280        return true;
6281    }
6282
6283    return false;
6284}
6285
6286static CSSValueID createFontWeightValueKeyword(int weight)
6287{
6288    ASSERT(!(weight % 100) && weight >= 100 && weight <= 900);
6289    CSSValueID value = static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1);
6290    ASSERT(value >= CSSValue100 && value <= CSSValue900);
6291    return value;
6292}
6293
6294bool CSSParser::parseFontWeight(bool important)
6295{
6296    CSSParserValue* value = m_valueList->current();
6297    if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
6298        addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important);
6299        return true;
6300    }
6301    if (validUnit(value, FInteger | FNonNeg, CSSQuirksMode)) {
6302        int weight = static_cast<int>(value->fValue);
6303        if (!(weight % 100) && weight >= 100 && weight <= 900) {
6304            addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(createFontWeightValueKeyword(weight)), important);
6305            return true;
6306        }
6307    }
6308    return false;
6309}
6310
6311bool CSSParser::parseFontFaceSrcURI(CSSValueList* valueList)
6312{
6313    RefPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string)));
6314
6315    CSSParserValue* value = m_valueList->next();
6316    if (!value) {
6317        valueList->append(uriValue.releaseNonNull());
6318        return true;
6319    }
6320    if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
6321        m_valueList->next();
6322        valueList->append(uriValue.releaseNonNull());
6323        return true;
6324    }
6325
6326    if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format("))
6327        return false;
6328
6329    // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
6330    // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
6331    CSSParserValueList* args = value->function->args.get();
6332    if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
6333        return false;
6334    uriValue->setFormat(args->current()->string);
6335    valueList->append(uriValue.releaseNonNull());
6336    value = m_valueList->next();
6337    if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
6338        m_valueList->next();
6339    return true;
6340}
6341
6342bool CSSParser::parseFontFaceSrcLocal(CSSValueList* valueList)
6343{
6344    CSSParserValueList* args = m_valueList->current()->function->args.get();
6345    if (!args || !args->size())
6346        return false;
6347
6348    if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING)
6349        valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string));
6350    else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
6351        StringBuilder builder;
6352        for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) {
6353            if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
6354                return false;
6355            if (!builder.isEmpty())
6356                builder.append(' ');
6357            builder.append(localValue->string);
6358        }
6359        valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
6360    } else
6361        return false;
6362
6363    if (CSSParserValue* value = m_valueList->next()) {
6364        if (value->unit == CSSParserValue::Operator && value->iValue == ',')
6365            m_valueList->next();
6366    }
6367    return true;
6368}
6369
6370bool CSSParser::parseFontFaceSrc()
6371{
6372    RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
6373
6374    while (CSSParserValue* value = m_valueList->current()) {
6375        if (value->unit == CSSPrimitiveValue::CSS_URI) {
6376            if (!parseFontFaceSrcURI(values.get()))
6377                return false;
6378        } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) {
6379            if (!parseFontFaceSrcLocal(values.get()))
6380                return false;
6381        } else
6382            return false;
6383    }
6384    if (!values->length())
6385        return false;
6386
6387    addProperty(CSSPropertySrc, values.release(), m_important);
6388    m_valueList->next();
6389    return true;
6390}
6391
6392bool CSSParser::parseFontFaceUnicodeRange()
6393{
6394    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
6395    bool failed = false;
6396    bool operatorExpected = false;
6397    for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
6398        if (operatorExpected) {
6399            if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
6400                continue;
6401            failed = true;
6402            break;
6403        }
6404        if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
6405            failed = true;
6406            break;
6407        }
6408
6409        String rangeString = m_valueList->current()->string;
6410        UChar32 from = 0;
6411        UChar32 to = 0;
6412        unsigned length = rangeString.length();
6413
6414        if (length < 3) {
6415            failed = true;
6416            break;
6417        }
6418
6419        unsigned i = 2;
6420        while (i < length) {
6421            UChar c = rangeString[i];
6422            if (c == '-' || c == '?')
6423                break;
6424            from *= 16;
6425            if (c >= '0' && c <= '9')
6426                from += c - '0';
6427            else if (c >= 'A' && c <= 'F')
6428                from += 10 + c - 'A';
6429            else if (c >= 'a' && c <= 'f')
6430                from += 10 + c - 'a';
6431            else {
6432                failed = true;
6433                break;
6434            }
6435            i++;
6436        }
6437        if (failed)
6438            break;
6439
6440        if (i == length)
6441            to = from;
6442        else if (rangeString[i] == '?') {
6443            unsigned span = 1;
6444            while (i < length && rangeString[i] == '?') {
6445                span *= 16;
6446                from *= 16;
6447                i++;
6448            }
6449            if (i < length)
6450                failed = true;
6451            to = from + span - 1;
6452        } else {
6453            if (length < i + 2) {
6454                failed = true;
6455                break;
6456            }
6457            i++;
6458            while (i < length) {
6459                UChar c = rangeString[i];
6460                to *= 16;
6461                if (c >= '0' && c <= '9')
6462                    to += c - '0';
6463                else if (c >= 'A' && c <= 'F')
6464                    to += 10 + c - 'A';
6465                else if (c >= 'a' && c <= 'f')
6466                    to += 10 + c - 'a';
6467                else {
6468                    failed = true;
6469                    break;
6470                }
6471                i++;
6472            }
6473            if (failed)
6474                break;
6475        }
6476        if (from <= to)
6477            values->append(CSSUnicodeRangeValue::create(from, to));
6478    }
6479    if (failed || !values->length())
6480        return false;
6481    addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
6482    return true;
6483}
6484
6485// Returns the number of characters which form a valid double
6486// and are terminated by the given terminator character
6487template <typename CharacterType>
6488static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
6489{
6490    int length = end - string;
6491    if (length < 1)
6492        return 0;
6493
6494    bool decimalMarkSeen = false;
6495    int processedLength = 0;
6496
6497    for (int i = 0; i < length; ++i) {
6498        if (string[i] == terminator) {
6499            processedLength = i;
6500            break;
6501        }
6502        if (!isASCIIDigit(string[i])) {
6503            if (!decimalMarkSeen && string[i] == '.')
6504                decimalMarkSeen = true;
6505            else
6506                return 0;
6507        }
6508    }
6509
6510    if (decimalMarkSeen && processedLength == 1)
6511        return 0;
6512
6513    return processedLength;
6514}
6515
6516// Returns the number of characters consumed for parsing a valid double
6517// terminated by the given terminator character
6518template <typename CharacterType>
6519static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value)
6520{
6521    int length = checkForValidDouble(string, end, terminator);
6522    if (!length)
6523        return 0;
6524
6525    int position = 0;
6526    double localValue = 0;
6527
6528    // The consumed characters here are guaranteed to be
6529    // ASCII digits with or without a decimal mark
6530    for (; position < length; ++position) {
6531        if (string[position] == '.')
6532            break;
6533        localValue = localValue * 10 + string[position] - '0';
6534    }
6535
6536    if (++position == length) {
6537        value = localValue;
6538        return length;
6539    }
6540
6541    double fraction = 0;
6542    double scale = 1;
6543
6544    while (position < length && scale < MAX_SCALE) {
6545        fraction = fraction * 10 + string[position++] - '0';
6546        scale *= 10;
6547    }
6548
6549    value = localValue + fraction / scale;
6550    return length;
6551}
6552
6553template <typename CharacterType>
6554static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
6555{
6556    const CharacterType* current = string;
6557    double localValue = 0;
6558    bool negative = false;
6559    while (current != end && isHTMLSpace(*current))
6560        current++;
6561    if (current != end && *current == '-') {
6562        negative = true;
6563        current++;
6564    }
6565    if (current == end || !isASCIIDigit(*current))
6566        return false;
6567    while (current != end && isASCIIDigit(*current)) {
6568        double newValue = localValue * 10 + *current++ - '0';
6569        if (newValue >= 255) {
6570            // Clamp values at 255.
6571            localValue = 255;
6572            while (current != end && isASCIIDigit(*current))
6573                ++current;
6574            break;
6575        }
6576        localValue = newValue;
6577    }
6578
6579    if (current == end)
6580        return false;
6581
6582    if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
6583        return false;
6584
6585    if (*current == '.') {
6586        // We already parsed the integral part, try to parse
6587        // the fraction part of the percentage value.
6588        double percentage = 0;
6589        int numCharactersParsed = parseDouble(current, end, '%', percentage);
6590        if (!numCharactersParsed)
6591            return false;
6592        current += numCharactersParsed;
6593        if (*current != '%')
6594            return false;
6595        localValue += percentage;
6596    }
6597
6598    if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
6599        return false;
6600
6601    if (*current == '%') {
6602        expect = CSSPrimitiveValue::CSS_PERCENTAGE;
6603        localValue = localValue / 100.0 * 256.0;
6604        // Clamp values at 255 for percentages over 100%
6605        if (localValue > 255)
6606            localValue = 255;
6607        current++;
6608    } else
6609        expect = CSSPrimitiveValue::CSS_NUMBER;
6610
6611    while (current != end && isHTMLSpace(*current))
6612        current++;
6613    if (current == end || *current++ != terminator)
6614        return false;
6615    // Clamp negative values at zero.
6616    value = negative ? 0 : static_cast<int>(localValue);
6617    string = current;
6618    return true;
6619}
6620
6621template <typename CharacterType>
6622static inline bool isTenthAlpha(const CharacterType* string, const int length)
6623{
6624    // "0.X"
6625    if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
6626        return true;
6627
6628    // ".X"
6629    if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
6630        return true;
6631
6632    return false;
6633}
6634
6635template <typename CharacterType>
6636static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
6637{
6638    while (string != end && isHTMLSpace(*string))
6639        string++;
6640
6641    bool negative = false;
6642
6643    if (string != end && *string == '-') {
6644        negative = true;
6645        string++;
6646    }
6647
6648    value = 0;
6649
6650    int length = end - string;
6651    if (length < 2)
6652        return false;
6653
6654    if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
6655        return false;
6656
6657    if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
6658        if (checkForValidDouble(string, end, terminator)) {
6659            value = negative ? 0 : 255;
6660            string = end;
6661            return true;
6662        }
6663        return false;
6664    }
6665
6666    if (length == 2 && string[0] != '.') {
6667        value = !negative && string[0] == '1' ? 255 : 0;
6668        string = end;
6669        return true;
6670    }
6671
6672    if (isTenthAlpha(string, length - 1)) {
6673        static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
6674        value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
6675        string = end;
6676        return true;
6677    }
6678
6679    double alpha = 0;
6680    if (!parseDouble(string, end, terminator, alpha))
6681        return false;
6682    value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
6683    string = end;
6684    return true;
6685}
6686
6687template <typename CharacterType>
6688static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
6689{
6690    if (length < 5)
6691        return false;
6692    return characters[4] == '('
6693        && isASCIIAlphaCaselessEqual(characters[0], 'r')
6694        && isASCIIAlphaCaselessEqual(characters[1], 'g')
6695        && isASCIIAlphaCaselessEqual(characters[2], 'b')
6696        && isASCIIAlphaCaselessEqual(characters[3], 'a');
6697}
6698
6699template <typename CharacterType>
6700static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
6701{
6702    if (length < 4)
6703        return false;
6704    return characters[3] == '('
6705        && isASCIIAlphaCaselessEqual(characters[0], 'r')
6706        && isASCIIAlphaCaselessEqual(characters[1], 'g')
6707        && isASCIIAlphaCaselessEqual(characters[2], 'b');
6708}
6709
6710template <typename CharacterType>
6711static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length , bool strict)
6712{
6713    CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
6714
6715    if (!strict && length >= 3) {
6716        if (characters[0] == '#') {
6717            if (Color::parseHexColor(characters + 1, length - 1, rgb))
6718                return true;
6719        } else {
6720            if (Color::parseHexColor(characters, length, rgb))
6721                return true;
6722        }
6723    }
6724
6725    // Try rgba() syntax.
6726    if (mightBeRGBA(characters, length)) {
6727        const CharacterType* current = characters + 5;
6728        const CharacterType* end = characters + length;
6729        int red;
6730        int green;
6731        int blue;
6732        int alpha;
6733
6734        if (!parseColorIntOrPercentage(current, end, ',', expect, red))
6735            return false;
6736        if (!parseColorIntOrPercentage(current, end, ',', expect, green))
6737            return false;
6738        if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
6739            return false;
6740        if (!parseAlphaValue(current, end, ')', alpha))
6741            return false;
6742        if (current != end)
6743            return false;
6744        rgb = makeRGBA(red, green, blue, alpha);
6745        return true;
6746    }
6747
6748    // Try rgb() syntax.
6749    if (mightBeRGB(characters, length)) {
6750        const CharacterType* current = characters + 4;
6751        const CharacterType* end = characters + length;
6752        int red;
6753        int green;
6754        int blue;
6755        if (!parseColorIntOrPercentage(current, end, ',', expect, red))
6756            return false;
6757        if (!parseColorIntOrPercentage(current, end, ',', expect, green))
6758            return false;
6759        if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
6760            return false;
6761        if (current != end)
6762            return false;
6763        rgb = makeRGB(red, green, blue);
6764        return true;
6765    }
6766
6767    return false;
6768}
6769
6770template<typename StringType>
6771bool CSSParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict)
6772{
6773    unsigned length = name.length();
6774    bool parseResult;
6775
6776    if (!length)
6777        return false;
6778
6779    if (name.is8Bit())
6780        parseResult = fastParseColorInternal(rgb, name.characters8(), length, strict);
6781    else
6782        parseResult = fastParseColorInternal(rgb, name.characters16(), length, strict);
6783
6784    if (parseResult)
6785        return true;
6786
6787    // Try named colors.
6788    Color tc;
6789    tc.setNamedColor(name);
6790    if (tc.isValid()) {
6791        rgb = tc.rgb();
6792        return true;
6793    }
6794    return false;
6795}
6796
6797inline double CSSParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc)
6798{
6799    const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue;
6800    if (releaseCalc == ReleaseParsedCalcValue)
6801        m_parsedCalculation.release();
6802    return result;
6803}
6804
6805bool CSSParser::isCalculation(CSSParserValue* value)
6806{
6807    return (value->unit == CSSParserValue::Function)
6808        && (equalIgnoringCase(value->function->name, "calc(")
6809            || equalIgnoringCase(value->function->name, "-webkit-calc(")
6810            || equalIgnoringCase(value->function->name, "-webkit-min(")
6811            || equalIgnoringCase(value->function->name, "-webkit-max("));
6812}
6813
6814inline int CSSParser::colorIntFromValue(CSSParserValue* v)
6815{
6816    bool isPercent;
6817
6818    if (m_parsedCalculation)
6819        isPercent = m_parsedCalculation->category() == CalcPercent;
6820    else
6821        isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
6822
6823    const double value = parsedDouble(v, ReleaseParsedCalcValue);
6824
6825    if (value <= 0.0)
6826        return 0;
6827
6828    if (isPercent) {
6829        if (value >= 100.0)
6830            return 255;
6831        return static_cast<int>(value * 256.0 / 100.0);
6832    }
6833
6834    if (value >= 255.0)
6835        return 255;
6836
6837    return static_cast<int>(value);
6838}
6839
6840bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
6841{
6842    CSSParserValueList* args = value->function->args.get();
6843    CSSParserValue* v = args->current();
6844    Units unitType = FUnknown;
6845    // Get the first value and its type
6846    if (validUnit(v, FInteger, CSSStrictMode))
6847        unitType = FInteger;
6848    else if (validUnit(v, FPercent, CSSStrictMode))
6849        unitType = FPercent;
6850    else
6851        return false;
6852
6853    colorArray[0] = colorIntFromValue(v);
6854    for (int i = 1; i < 3; i++) {
6855        v = args->next();
6856        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6857            return false;
6858        v = args->next();
6859        if (!validUnit(v, unitType, CSSStrictMode))
6860            return false;
6861        colorArray[i] = colorIntFromValue(v);
6862    }
6863    if (parseAlpha) {
6864        v = args->next();
6865        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6866            return false;
6867        v = args->next();
6868        if (!validUnit(v, FNumber, CSSStrictMode))
6869            return false;
6870        const double value = parsedDouble(v, ReleaseParsedCalcValue);
6871        // Convert the floating pointer number of alpha to an integer in the range [0, 256),
6872        // with an equal distribution across all 256 values.
6873        colorArray[3] = static_cast<int>(std::max<double>(0, std::min<double>(1, value)) * nextafter(256.0, 0.0));
6874    }
6875    return true;
6876}
6877
6878// The CSS3 specification defines the format of a HSL color as
6879// hsl(<number>, <percent>, <percent>)
6880// and with alpha, the format is
6881// hsla(<number>, <percent>, <percent>, <number>)
6882// The first value, HUE, is in an angle with a value between 0 and 360
6883bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
6884{
6885    CSSParserValueList* args = value->function->args.get();
6886    CSSParserValue* v = args->current();
6887    // Get the first value
6888    if (!validUnit(v, FNumber, CSSStrictMode))
6889        return false;
6890    // normalize the Hue value and change it to be between 0 and 1.0
6891    colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0;
6892    for (int i = 1; i < 3; i++) {
6893        v = args->next();
6894        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6895            return false;
6896        v = args->next();
6897        if (!validUnit(v, FPercent, CSSStrictMode))
6898            return false;
6899        colorArray[i] = std::max<double>(0, std::min<double>(100, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0
6900    }
6901    if (parseAlpha) {
6902        v = args->next();
6903        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6904            return false;
6905        v = args->next();
6906        if (!validUnit(v, FNumber, CSSStrictMode))
6907            return false;
6908        colorArray[3] = std::max<double>(0, std::min<double>(1, parsedDouble(v, ReleaseParsedCalcValue)));
6909    }
6910    return true;
6911}
6912
6913PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value)
6914{
6915    RGBA32 c = Color::transparent;
6916    if (!parseColorFromValue(value ? value : m_valueList->current(), c))
6917        return 0;
6918    return cssValuePool().createColorValue(c);
6919}
6920
6921bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
6922{
6923    if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
6924        && value->fValue >= 0. && value->fValue < 1000000.) {
6925        String str = String::format("%06d", static_cast<int>((value->fValue+.5)));
6926        // FIXME: This should be strict parsing for SVG as well.
6927        if (!fastParseColor(c, str, inStrictMode()))
6928            return false;
6929    } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
6930                value->unit == CSSPrimitiveValue::CSS_IDENT ||
6931                (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
6932        if (!fastParseColor(c, value->string, inStrictMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
6933            return false;
6934    } else if (value->unit == CSSParserValue::Function &&
6935                value->function->args != 0 &&
6936                value->function->args->size() == 5 /* rgb + two commas */ &&
6937                equalIgnoringCase(value->function->name, "rgb(")) {
6938        int colorValues[3];
6939        if (!parseColorParameters(value, colorValues, false))
6940            return false;
6941        c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
6942    } else {
6943        if (value->unit == CSSParserValue::Function &&
6944                value->function->args != 0 &&
6945                value->function->args->size() == 7 /* rgba + three commas */ &&
6946                equalIgnoringCase(value->function->name, "rgba(")) {
6947            int colorValues[4];
6948            if (!parseColorParameters(value, colorValues, true))
6949                return false;
6950            c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
6951        } else if (value->unit == CSSParserValue::Function &&
6952                    value->function->args != 0 &&
6953                    value->function->args->size() == 5 /* hsl + two commas */ &&
6954                    equalIgnoringCase(value->function->name, "hsl(")) {
6955            double colorValues[3];
6956            if (!parseHSLParameters(value, colorValues, false))
6957                return false;
6958            c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
6959        } else if (value->unit == CSSParserValue::Function &&
6960                    value->function->args != 0 &&
6961                    value->function->args->size() == 7 /* hsla + three commas */ &&
6962                    equalIgnoringCase(value->function->name, "hsla(")) {
6963            double colorValues[4];
6964            if (!parseHSLParameters(value, colorValues, true))
6965                return false;
6966            c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
6967        } else
6968            return false;
6969    }
6970
6971    return true;
6972}
6973
6974// This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
6975// without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
6976struct ShadowParseContext {
6977    ShadowParseContext(CSSPropertyID prop, CSSParser* parser)
6978        : property(prop)
6979        , m_parser(parser)
6980        , allowX(true)
6981        , allowY(false)
6982        , allowBlur(false)
6983        , allowSpread(false)
6984        , allowColor(true)
6985        , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
6986        , allowBreak(true)
6987    {
6988    }
6989
6990    bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
6991
6992    void commitValue()
6993    {
6994        // Handle the ,, case gracefully by doing nothing.
6995        if (x || y || blur || spread || color || style) {
6996            if (!values)
6997                values = CSSValueList::createCommaSeparated();
6998
6999            // Construct the current shadow value and add it to the list.
7000            values->append(CSSShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
7001        }
7002
7003        // Now reset for the next shadow value.
7004        x = 0;
7005        y = 0;
7006        blur = 0;
7007        spread = 0;
7008        style = 0;
7009        color = 0;
7010
7011        allowX = true;
7012        allowColor = true;
7013        allowBreak = true;
7014        allowY = false;
7015        allowBlur = false;
7016        allowSpread = false;
7017        allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
7018    }
7019
7020    void commitLength(CSSParserValue* v)
7021    {
7022        RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
7023
7024        if (allowX) {
7025            x = val.release();
7026            allowX = false;
7027            allowY = true;
7028            allowColor = false;
7029            allowStyle = false;
7030            allowBreak = false;
7031        } else if (allowY) {
7032            y = val.release();
7033            allowY = false;
7034            allowBlur = true;
7035            allowColor = true;
7036            allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
7037            allowBreak = true;
7038        } else if (allowBlur) {
7039            blur = val.release();
7040            allowBlur = false;
7041            allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
7042        } else if (allowSpread) {
7043            spread = val.release();
7044            allowSpread = false;
7045        }
7046    }
7047
7048    void commitColor(PassRefPtr<CSSPrimitiveValue> val)
7049    {
7050        color = val;
7051        allowColor = false;
7052        if (allowX) {
7053            allowStyle = false;
7054            allowBreak = false;
7055        } else {
7056            allowBlur = false;
7057            allowSpread = false;
7058            allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
7059        }
7060    }
7061
7062    void commitStyle(CSSParserValue* v)
7063    {
7064        style = cssValuePool().createIdentifierValue(v->id);
7065        allowStyle = false;
7066        if (allowX)
7067            allowBreak = false;
7068        else {
7069            allowBlur = false;
7070            allowSpread = false;
7071            allowColor = false;
7072        }
7073    }
7074
7075    CSSPropertyID property;
7076    CSSParser* m_parser;
7077
7078    RefPtr<CSSValueList> values;
7079    RefPtr<CSSPrimitiveValue> x;
7080    RefPtr<CSSPrimitiveValue> y;
7081    RefPtr<CSSPrimitiveValue> blur;
7082    RefPtr<CSSPrimitiveValue> spread;
7083    RefPtr<CSSPrimitiveValue> style;
7084    RefPtr<CSSPrimitiveValue> color;
7085
7086    bool allowX;
7087    bool allowY;
7088    bool allowBlur;
7089    bool allowSpread;
7090    bool allowColor;
7091    bool allowStyle; // inset or not.
7092    bool allowBreak;
7093};
7094
7095PassRefPtr<CSSValueList> CSSParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId)
7096{
7097    ShadowParseContext context(propId, this);
7098    CSSParserValue* val;
7099    while ((val = valueList->current())) {
7100        // Check for a comma break first.
7101        if (val->unit == CSSParserValue::Operator) {
7102            if (val->iValue != ',' || !context.allowBreak)
7103                // Other operators aren't legal or we aren't done with the current shadow
7104                // value.  Treat as invalid.
7105                return 0;
7106            // -webkit-svg-shadow does not support multiple values.
7107            if (propId == CSSPropertyWebkitSvgShadow)
7108                return 0;
7109            // The value is good.  Commit it.
7110            context.commitValue();
7111        } else if (validUnit(val, FLength, CSSStrictMode)) {
7112            // We required a length and didn't get one. Invalid.
7113            if (!context.allowLength())
7114                return 0;
7115
7116            // Blur radius must be non-negative.
7117            if (context.allowBlur && !validUnit(val, FLength | FNonNeg, CSSStrictMode))
7118                return 0;
7119
7120            // A length is allowed here.  Construct the value and add it.
7121            context.commitLength(val);
7122        } else if (val->id == CSSValueInset) {
7123            if (!context.allowStyle)
7124                return 0;
7125
7126            context.commitStyle(val);
7127        } else {
7128            // The only other type of value that's ok is a color value.
7129            RefPtr<CSSPrimitiveValue> parsedColor;
7130            bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu
7131                            || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode())
7132                            || val->id == CSSValueCurrentcolor);
7133            if (isColor) {
7134                if (!context.allowColor)
7135                    return 0;
7136                parsedColor = cssValuePool().createIdentifierValue(val->id);
7137            }
7138
7139            if (!parsedColor)
7140                // It's not built-in. Try to parse it as a color.
7141                parsedColor = parseColor(val);
7142
7143            if (!parsedColor || !context.allowColor)
7144                return 0; // This value is not a color or length and is invalid or
7145                          // it is a color, but a color isn't allowed at this point.
7146
7147            context.commitColor(parsedColor.release());
7148        }
7149
7150        valueList->next();
7151    }
7152
7153    if (context.allowBreak) {
7154        context.commitValue();
7155        if (context.values && context.values->length())
7156            return context.values.release();
7157    }
7158
7159    return 0;
7160}
7161
7162bool CSSParser::parseReflect(CSSPropertyID propId, bool important)
7163{
7164    // box-reflect: <direction> <offset> <mask>
7165
7166    // Direction comes first.
7167    CSSParserValue* val = m_valueList->current();
7168    RefPtr<CSSPrimitiveValue> direction;
7169    switch (val->id) {
7170        case CSSValueAbove:
7171        case CSSValueBelow:
7172        case CSSValueLeft:
7173        case CSSValueRight:
7174            direction = cssValuePool().createIdentifierValue(val->id);
7175            break;
7176        default:
7177            return false;
7178    }
7179
7180    // The offset comes next.
7181    val = m_valueList->next();
7182    RefPtr<CSSPrimitiveValue> offset;
7183    if (!val)
7184        offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
7185    else {
7186        if (!validUnit(val, FLength | FPercent))
7187            return false;
7188        offset = createPrimitiveNumericValue(val);
7189    }
7190
7191    // Now for the mask.
7192    RefPtr<CSSValue> mask;
7193    val = m_valueList->next();
7194    if (val) {
7195        if (!parseBorderImage(propId, mask))
7196            return false;
7197    }
7198
7199    addProperty(propId, CSSReflectValue::create(direction.release(), offset.release(), mask.release()), important);
7200    m_valueList->next();
7201    return true;
7202}
7203
7204bool CSSParser::parseFlex(CSSParserValueList* args, bool important)
7205{
7206    if (!args || !args->size() || args->size() > 3)
7207        return false;
7208    static const double unsetValue = -1;
7209    double flexGrow = unsetValue;
7210    double flexShrink = unsetValue;
7211    RefPtr<CSSPrimitiveValue> flexBasis;
7212
7213    while (CSSParserValue* arg = args->current()) {
7214        if (validUnit(arg, FNumber | FNonNeg)) {
7215            if (flexGrow == unsetValue)
7216                flexGrow = arg->fValue;
7217            else if (flexShrink == unsetValue)
7218                flexShrink = arg->fValue;
7219            else if (!arg->fValue) {
7220                // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
7221                flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
7222            } else {
7223                // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
7224                return false;
7225            }
7226        } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg)))
7227            flexBasis = parseValidPrimitive(arg->id, arg);
7228        else {
7229            // Not a valid arg for flex.
7230            return false;
7231        }
7232        args->next();
7233    }
7234
7235    if (flexGrow == unsetValue)
7236        flexGrow = 1;
7237    if (flexShrink == unsetValue)
7238        flexShrink = 1;
7239    if (!flexBasis)
7240        flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
7241
7242    addProperty(CSSPropertyWebkitFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
7243    addProperty(CSSPropertyWebkitFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
7244    addProperty(CSSPropertyWebkitFlexBasis, flexBasis, important);
7245    return true;
7246}
7247
7248struct BorderImageParseContext {
7249    BorderImageParseContext()
7250    : m_canAdvance(false)
7251    , m_allowCommit(true)
7252    , m_allowImage(true)
7253    , m_allowImageSlice(true)
7254    , m_allowRepeat(true)
7255    , m_allowForwardSlashOperator(false)
7256    , m_requireWidth(false)
7257    , m_requireOutset(false)
7258    {}
7259
7260    bool canAdvance() const { return m_canAdvance; }
7261    void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
7262
7263    bool allowCommit() const { return m_allowCommit; }
7264    bool allowImage() const { return m_allowImage; }
7265    bool allowImageSlice() const { return m_allowImageSlice; }
7266    bool allowRepeat() const { return m_allowRepeat; }
7267    bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; }
7268
7269    bool requireWidth() const { return m_requireWidth; }
7270    bool requireOutset() const { return m_requireOutset; }
7271
7272    void commitImage(PassRefPtr<CSSValue> image)
7273    {
7274        m_image = image;
7275        m_canAdvance = true;
7276        m_allowCommit = true;
7277        m_allowImage = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
7278        m_allowImageSlice = !m_imageSlice;
7279        m_allowRepeat = !m_repeat;
7280    }
7281    void commitImageSlice(PassRefPtr<CSSBorderImageSliceValue> slice)
7282    {
7283        m_imageSlice = slice;
7284        m_canAdvance = true;
7285        m_allowCommit = m_allowForwardSlashOperator = true;
7286        m_allowImageSlice = m_requireWidth = m_requireOutset = false;
7287        m_allowImage = !m_image;
7288        m_allowRepeat = !m_repeat;
7289    }
7290    void commitForwardSlashOperator()
7291    {
7292        m_canAdvance = true;
7293        m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowForwardSlashOperator = false;
7294        if (!m_borderSlice) {
7295            m_requireWidth = true;
7296            m_requireOutset = false;
7297        } else {
7298            m_requireOutset = true;
7299            m_requireWidth = false;
7300        }
7301    }
7302    void commitBorderWidth(PassRefPtr<CSSPrimitiveValue> slice)
7303    {
7304        m_borderSlice = slice;
7305        m_canAdvance = true;
7306        m_allowCommit = m_allowForwardSlashOperator = true;
7307        m_allowImageSlice = m_requireWidth = m_requireOutset = false;
7308        m_allowImage = !m_image;
7309        m_allowRepeat = !m_repeat;
7310    }
7311    void commitBorderOutset(PassRefPtr<CSSPrimitiveValue> outset)
7312    {
7313        m_outset = outset;
7314        m_canAdvance = true;
7315        m_allowCommit = true;
7316        m_allowImageSlice = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
7317        m_allowImage = !m_image;
7318        m_allowRepeat = !m_repeat;
7319    }
7320    void commitRepeat(PassRefPtr<CSSValue> repeat)
7321    {
7322        m_repeat = repeat;
7323        m_canAdvance = true;
7324        m_allowCommit = true;
7325        m_allowRepeat = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
7326        m_allowImageSlice = !m_imageSlice;
7327        m_allowImage = !m_image;
7328    }
7329
7330    PassRefPtr<CSSValue> commitWebKitBorderImage()
7331    {
7332        return createBorderImageValue(m_image, m_imageSlice, m_borderSlice, m_outset, m_repeat);
7333    }
7334
7335    void commitBorderImage(CSSParser* parser, bool important)
7336    {
7337        commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
7338        commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice, important);
7339        commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice, important);
7340        commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset, important);
7341        commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important);
7342    }
7343
7344    void commitBorderImageProperty(CSSPropertyID propId, CSSParser* parser, PassRefPtr<CSSValue> value, bool important)
7345    {
7346        if (value)
7347            parser->addProperty(propId, value, important);
7348        else
7349            parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true);
7350    }
7351
7352    bool m_canAdvance;
7353
7354    bool m_allowCommit;
7355    bool m_allowImage;
7356    bool m_allowImageSlice;
7357    bool m_allowRepeat;
7358    bool m_allowForwardSlashOperator;
7359
7360    bool m_requireWidth;
7361    bool m_requireOutset;
7362
7363    RefPtr<CSSValue> m_image;
7364    RefPtr<CSSBorderImageSliceValue> m_imageSlice;
7365    RefPtr<CSSPrimitiveValue> m_borderSlice;
7366    RefPtr<CSSPrimitiveValue> m_outset;
7367
7368    RefPtr<CSSValue> m_repeat;
7369};
7370
7371bool CSSParser::parseBorderImage(CSSPropertyID propId, RefPtr<CSSValue>& result, bool important)
7372{
7373    ShorthandScope scope(this, propId);
7374    BorderImageParseContext context;
7375    while (CSSParserValue* val = m_valueList->current()) {
7376        context.setCanAdvance(false);
7377
7378        if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(val))
7379            context.commitForwardSlashOperator();
7380
7381        if (!context.canAdvance() && context.allowImage()) {
7382            if (val->unit == CSSPrimitiveValue::CSS_URI)
7383                context.commitImage(CSSImageValue::create(completeURL(val->string)));
7384            else if (isGeneratedImageValue(val)) {
7385                RefPtr<CSSValue> value;
7386                if (parseGeneratedImage(m_valueList.get(), value))
7387                    context.commitImage(value.release());
7388                else
7389                    return false;
7390#if ENABLE(CSS_IMAGE_SET)
7391            } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
7392                RefPtr<CSSValue> value = parseImageSet();
7393                if (value)
7394                    context.commitImage(value.release());
7395                else
7396                    return false;
7397#endif
7398            } else if (val->id == CSSValueNone)
7399                context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone));
7400        }
7401
7402        if (!context.canAdvance() && context.allowImageSlice()) {
7403            RefPtr<CSSBorderImageSliceValue> imageSlice;
7404            if (parseBorderImageSlice(propId, imageSlice))
7405                context.commitImageSlice(imageSlice.release());
7406        }
7407
7408        if (!context.canAdvance() && context.allowRepeat()) {
7409            RefPtr<CSSValue> repeat;
7410            if (parseBorderImageRepeat(repeat))
7411                context.commitRepeat(repeat.release());
7412        }
7413
7414        if (!context.canAdvance() && context.requireWidth()) {
7415            RefPtr<CSSPrimitiveValue> borderSlice;
7416            if (parseBorderImageWidth(borderSlice))
7417                context.commitBorderWidth(borderSlice.release());
7418        }
7419
7420        if (!context.canAdvance() && context.requireOutset()) {
7421            RefPtr<CSSPrimitiveValue> borderOutset;
7422            if (parseBorderImageOutset(borderOutset))
7423                context.commitBorderOutset(borderOutset.release());
7424        }
7425
7426        if (!context.canAdvance())
7427            return false;
7428
7429        m_valueList->next();
7430    }
7431
7432    if (context.allowCommit()) {
7433        if (propId == CSSPropertyBorderImage)
7434            context.commitBorderImage(this, important);
7435        else
7436            // Need to fully commit as a single value.
7437            result = context.commitWebKitBorderImage();
7438        return true;
7439    }
7440
7441    return false;
7442}
7443
7444static bool isBorderImageRepeatKeyword(int id)
7445{
7446    return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
7447}
7448
7449bool CSSParser::parseBorderImageRepeat(RefPtr<CSSValue>& result)
7450{
7451    RefPtr<CSSPrimitiveValue> firstValue;
7452    RefPtr<CSSPrimitiveValue> secondValue;
7453    CSSParserValue* val = m_valueList->current();
7454    if (!val)
7455        return false;
7456    if (isBorderImageRepeatKeyword(val->id))
7457        firstValue = cssValuePool().createIdentifierValue(val->id);
7458    else
7459        return false;
7460
7461    val = m_valueList->next();
7462    if (val) {
7463        if (isBorderImageRepeatKeyword(val->id))
7464            secondValue = cssValuePool().createIdentifierValue(val->id);
7465        else if (!inShorthand()) {
7466            // If we're not parsing a shorthand then we are invalid.
7467            return false;
7468        } else {
7469            // We need to rewind the value list, so that when its advanced we'll
7470            // end up back at this value.
7471            m_valueList->previous();
7472            secondValue = firstValue;
7473        }
7474    } else
7475        secondValue = firstValue;
7476
7477    result = createPrimitiveValuePair(firstValue, secondValue);
7478    return true;
7479}
7480
7481class BorderImageSliceParseContext {
7482public:
7483    BorderImageSliceParseContext(CSSParser* parser)
7484    : m_parser(parser)
7485    , m_allowNumber(true)
7486    , m_allowFill(true)
7487    , m_allowFinalCommit(false)
7488    , m_fill(false)
7489    { }
7490
7491    bool allowNumber() const { return m_allowNumber; }
7492    bool allowFill() const { return m_allowFill; }
7493    bool allowFinalCommit() const { return m_allowFinalCommit; }
7494    CSSPrimitiveValue* top() const { return m_top.get(); }
7495
7496    void commitNumber(CSSParserValue* v)
7497    {
7498        RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
7499        if (!m_top)
7500            m_top = val;
7501        else if (!m_right)
7502            m_right = val;
7503        else if (!m_bottom)
7504            m_bottom = val;
7505        else {
7506            ASSERT(!m_left);
7507            m_left = val;
7508        }
7509
7510        m_allowNumber = !m_left;
7511        m_allowFinalCommit = true;
7512    }
7513
7514    void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; }
7515
7516    PassRefPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
7517    {
7518        // We need to clone and repeat values for any omissions.
7519        ASSERT(m_top);
7520        if (!m_right) {
7521            m_right = m_top;
7522            m_bottom = m_top;
7523            m_left = m_top;
7524        }
7525        if (!m_bottom) {
7526            m_bottom = m_top;
7527            m_left = m_right;
7528        }
7529        if (!m_left)
7530            m_left = m_right;
7531
7532        // Now build a rect value to hold all four of our primitive values.
7533        RefPtr<Quad> quad = Quad::create();
7534        quad->setTop(m_top);
7535        quad->setRight(m_right);
7536        quad->setBottom(m_bottom);
7537        quad->setLeft(m_left);
7538
7539        // Make our new border image value now.
7540        return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill);
7541    }
7542
7543private:
7544    CSSParser* m_parser;
7545
7546    bool m_allowNumber;
7547    bool m_allowFill;
7548    bool m_allowFinalCommit;
7549
7550    RefPtr<CSSPrimitiveValue> m_top;
7551    RefPtr<CSSPrimitiveValue> m_right;
7552    RefPtr<CSSPrimitiveValue> m_bottom;
7553    RefPtr<CSSPrimitiveValue> m_left;
7554
7555    bool m_fill;
7556};
7557
7558bool CSSParser::parseBorderImageSlice(CSSPropertyID propId, RefPtr<CSSBorderImageSliceValue>& result)
7559{
7560    BorderImageSliceParseContext context(this);
7561    CSSParserValue* val;
7562    while ((val = m_valueList->current())) {
7563        // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
7564        if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, CSSStrictMode)) {
7565            context.commitNumber(val);
7566        } else if (context.allowFill() && val->id == CSSValueFill)
7567            context.commitFill();
7568        else if (!inShorthand()) {
7569            // If we're not parsing a shorthand then we are invalid.
7570            return false;
7571        } else {
7572            if (context.allowFinalCommit()) {
7573                // We're going to successfully parse, but we don't want to consume this token.
7574                m_valueList->previous();
7575            }
7576            break;
7577        }
7578        m_valueList->next();
7579    }
7580
7581    if (context.allowFinalCommit()) {
7582        // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
7583        // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
7584        if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
7585            context.commitFill();
7586
7587        // Need to fully commit as a single value.
7588        result = context.commitBorderImageSlice();
7589        return true;
7590    }
7591
7592    return false;
7593}
7594
7595class BorderImageQuadParseContext {
7596public:
7597    BorderImageQuadParseContext(CSSParser* parser)
7598    : m_parser(parser)
7599    , m_allowNumber(true)
7600    , m_allowFinalCommit(false)
7601    { }
7602
7603    bool allowNumber() const { return m_allowNumber; }
7604    bool allowFinalCommit() const { return m_allowFinalCommit; }
7605    CSSPrimitiveValue* top() const { return m_top.get(); }
7606
7607    void commitNumber(CSSParserValue* v)
7608    {
7609        RefPtr<CSSPrimitiveValue> val;
7610        if (v->id == CSSValueAuto)
7611            val = cssValuePool().createIdentifierValue(v->id);
7612        else
7613            val = m_parser->createPrimitiveNumericValue(v);
7614
7615        if (!m_top)
7616            m_top = val;
7617        else if (!m_right)
7618            m_right = val;
7619        else if (!m_bottom)
7620            m_bottom = val;
7621        else {
7622            ASSERT(!m_left);
7623            m_left = val;
7624        }
7625
7626        m_allowNumber = !m_left;
7627        m_allowFinalCommit = true;
7628    }
7629
7630    void setAllowFinalCommit() { m_allowFinalCommit = true; }
7631    void setTop(PassRefPtr<CSSPrimitiveValue> val) { m_top = val; }
7632
7633    PassRefPtr<CSSPrimitiveValue> commitBorderImageQuad()
7634    {
7635        // We need to clone and repeat values for any omissions.
7636        ASSERT(m_top);
7637        if (!m_right) {
7638            m_right = m_top;
7639            m_bottom = m_top;
7640            m_left = m_top;
7641        }
7642        if (!m_bottom) {
7643            m_bottom = m_top;
7644            m_left = m_right;
7645        }
7646        if (!m_left)
7647            m_left = m_right;
7648
7649        // Now build a quad value to hold all four of our primitive values.
7650        RefPtr<Quad> quad = Quad::create();
7651        quad->setTop(m_top);
7652        quad->setRight(m_right);
7653        quad->setBottom(m_bottom);
7654        quad->setLeft(m_left);
7655
7656        // Make our new value now.
7657        return cssValuePool().createValue(quad.release());
7658    }
7659
7660private:
7661    CSSParser* m_parser;
7662
7663    bool m_allowNumber;
7664    bool m_allowFinalCommit;
7665
7666    RefPtr<CSSPrimitiveValue> m_top;
7667    RefPtr<CSSPrimitiveValue> m_right;
7668    RefPtr<CSSPrimitiveValue> m_bottom;
7669    RefPtr<CSSPrimitiveValue> m_left;
7670};
7671
7672bool CSSParser::parseBorderImageQuad(Units validUnits, RefPtr<CSSPrimitiveValue>& result)
7673{
7674    BorderImageQuadParseContext context(this);
7675    CSSParserValue* val;
7676    while ((val = m_valueList->current())) {
7677        if (context.allowNumber() && (validUnit(val, validUnits, CSSStrictMode) || val->id == CSSValueAuto)) {
7678            context.commitNumber(val);
7679        } else if (!inShorthand()) {
7680            // If we're not parsing a shorthand then we are invalid.
7681            return false;
7682        } else {
7683            if (context.allowFinalCommit())
7684                m_valueList->previous(); // The shorthand loop will advance back to this point.
7685            break;
7686        }
7687        m_valueList->next();
7688    }
7689
7690    if (context.allowFinalCommit()) {
7691        // Need to fully commit as a single value.
7692        result = context.commitBorderImageQuad();
7693        return true;
7694    }
7695    return false;
7696}
7697
7698bool CSSParser::parseBorderImageWidth(RefPtr<CSSPrimitiveValue>& result)
7699{
7700    return parseBorderImageQuad(FLength | FInteger | FNonNeg | FPercent, result);
7701}
7702
7703bool CSSParser::parseBorderImageOutset(RefPtr<CSSPrimitiveValue>& result)
7704{
7705    return parseBorderImageQuad(FLength | FInteger | FNonNeg, result);
7706}
7707
7708bool CSSParser::parseBorderRadius(CSSPropertyID propId, bool important)
7709{
7710    unsigned num = m_valueList->size();
7711    if (num > 9)
7712        return false;
7713
7714    ShorthandScope scope(this, propId);
7715    RefPtr<CSSPrimitiveValue> radii[2][4];
7716
7717    unsigned indexAfterSlash = 0;
7718    for (unsigned i = 0; i < num; ++i) {
7719        CSSParserValue* value = m_valueList->valueAt(i);
7720        if (value->unit == CSSParserValue::Operator) {
7721            if (value->iValue != '/')
7722                return false;
7723
7724            if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
7725                return false;
7726
7727            indexAfterSlash = i + 1;
7728            completeBorderRadii(radii[0]);
7729            continue;
7730        }
7731
7732        if (i - indexAfterSlash >= 4)
7733            return false;
7734
7735        if (!validUnit(value, FLength | FPercent | FNonNeg))
7736            return false;
7737
7738        RefPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
7739
7740        if (!indexAfterSlash) {
7741            radii[0][i] = radius;
7742
7743            // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
7744            if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
7745                indexAfterSlash = 1;
7746                completeBorderRadii(radii[0]);
7747            }
7748        } else
7749            radii[1][i - indexAfterSlash] = radius.release();
7750    }
7751
7752    if (!indexAfterSlash) {
7753        completeBorderRadii(radii[0]);
7754        for (unsigned i = 0; i < 4; ++i)
7755            radii[1][i] = radii[0][i];
7756    } else
7757        completeBorderRadii(radii[1]);
7758
7759    ImplicitScope implicitScope(this, PropertyImplicit);
7760    addProperty(CSSPropertyBorderTopLeftRadius, createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()), important);
7761    addProperty(CSSPropertyBorderTopRightRadius, createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()), important);
7762    addProperty(CSSPropertyBorderBottomRightRadius, createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()), important);
7763    addProperty(CSSPropertyBorderBottomLeftRadius, createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()), important);
7764    return true;
7765}
7766
7767bool CSSParser::parseAspectRatio(bool important)
7768{
7769    unsigned num = m_valueList->size();
7770    if (num == 1) {
7771        CSSValueID valueId = m_valueList->valueAt(0)->id;
7772        if (valueId == CSSValueAuto || valueId == CSSValueFromDimensions || valueId == CSSValueFromIntrinsic) {
7773            addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(valueId), important);
7774            return true;
7775        }
7776    }
7777
7778    if (num != 3)
7779        return false;
7780
7781    CSSParserValue* lvalue = m_valueList->valueAt(0);
7782    CSSParserValue* op = m_valueList->valueAt(1);
7783    CSSParserValue* rvalue = m_valueList->valueAt(2);
7784
7785    if (!isForwardSlashOperator(op))
7786        return false;
7787
7788    if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
7789        return false;
7790
7791    if (!lvalue->fValue || !rvalue->fValue)
7792        return false;
7793
7794    addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important);
7795
7796    return true;
7797}
7798
7799bool CSSParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important)
7800{
7801    enum { ID, VAL } state = ID;
7802
7803    RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
7804    RefPtr<CSSPrimitiveValue> counterName;
7805
7806    while (true) {
7807        CSSParserValue* val = m_valueList->current();
7808        switch (state) {
7809            case ID:
7810                if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
7811                    counterName = createPrimitiveStringValue(val);
7812                    state = VAL;
7813                    m_valueList->next();
7814                    continue;
7815                }
7816                break;
7817            case VAL: {
7818                int i = defaultValue;
7819                if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
7820                    i = clampToInteger(val->fValue);
7821                    m_valueList->next();
7822                }
7823
7824                list->append(createPrimitiveValuePair(counterName.release(),
7825                    cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER)));
7826                state = ID;
7827                continue;
7828            }
7829        }
7830        break;
7831    }
7832
7833    if (list->length() > 0) {
7834        addProperty(propId, list.release(), important);
7835        return true;
7836    }
7837
7838    return false;
7839}
7840
7841// This should go away once we drop support for -webkit-gradient
7842static PassRefPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
7843{
7844    RefPtr<CSSPrimitiveValue> result;
7845    if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
7846        if ((equalIgnoringCase(a, "left") && horizontal)
7847            || (equalIgnoringCase(a, "top") && !horizontal))
7848            result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
7849        else if ((equalIgnoringCase(a, "right") && horizontal)
7850                 || (equalIgnoringCase(a, "bottom") && !horizontal))
7851            result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
7852        else if (equalIgnoringCase(a, "center"))
7853            result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
7854    } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7855        result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(a->unit));
7856    return result;
7857}
7858
7859static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
7860{
7861    if (a->unit != CSSParserValue::Function)
7862        return false;
7863
7864    if (!equalIgnoringCase(a->function->name, "from(") &&
7865        !equalIgnoringCase(a->function->name, "to(") &&
7866        !equalIgnoringCase(a->function->name, "color-stop("))
7867        return false;
7868
7869    CSSParserValueList* args = a->function->args.get();
7870    if (!args)
7871        return false;
7872
7873    if (equalIgnoringCase(a->function->name, "from(")
7874        || equalIgnoringCase(a->function->name, "to(")) {
7875        // The "from" and "to" stops expect 1 argument.
7876        if (args->size() != 1)
7877            return false;
7878
7879        if (equalIgnoringCase(a->function->name, "from("))
7880            stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
7881        else
7882            stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
7883
7884        CSSValueID id = args->current()->id;
7885        if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
7886            stop.m_color = cssValuePool().createIdentifierValue(id);
7887        else
7888            stop.m_color = p->parseColor(args->current());
7889        if (!stop.m_color)
7890            return false;
7891    }
7892
7893    // The "color-stop" function expects 3 arguments.
7894    if (equalIgnoringCase(a->function->name, "color-stop(")) {
7895        if (args->size() != 3)
7896            return false;
7897
7898        CSSParserValue* stopArg = args->current();
7899        if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7900            stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
7901        else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
7902            stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
7903        else
7904            return false;
7905
7906        stopArg = args->next();
7907        if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
7908            return false;
7909
7910        stopArg = args->next();
7911        CSSValueID id = stopArg->id;
7912        if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
7913            stop.m_color = cssValuePool().createIdentifierValue(id);
7914        else
7915            stop.m_color = p->parseColor(stopArg);
7916        if (!stop.m_color)
7917            return false;
7918    }
7919
7920    return true;
7921}
7922
7923bool CSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient)
7924{
7925    // Walk the arguments.
7926    CSSParserValueList* args = valueList->current()->function->args.get();
7927    if (!args || args->size() == 0)
7928        return false;
7929
7930    // The first argument is the gradient type.  It is an identifier.
7931    CSSGradientType gradientType;
7932    CSSParserValue* a = args->current();
7933    if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
7934        return false;
7935    if (equalIgnoringCase(a, "linear"))
7936        gradientType = CSSDeprecatedLinearGradient;
7937    else if (equalIgnoringCase(a, "radial"))
7938        gradientType = CSSDeprecatedRadialGradient;
7939    else
7940        return false;
7941
7942    RefPtr<CSSGradientValue> result;
7943    switch (gradientType) {
7944    case CSSDeprecatedLinearGradient:
7945        result = CSSLinearGradientValue::create(NonRepeating, gradientType);
7946        break;
7947    case CSSDeprecatedRadialGradient:
7948        result = CSSRadialGradientValue::create(NonRepeating, gradientType);
7949        break;
7950    default:
7951        // The rest of the gradient types shouldn't appear here.
7952        ASSERT_NOT_REACHED();
7953    }
7954
7955    // Comma.
7956    a = args->next();
7957    if (!isComma(a))
7958        return false;
7959
7960    // Next comes the starting point for the gradient as an x y pair.  There is no
7961    // comma between the x and the y values.
7962    // First X.  It can be left, right, number or percent.
7963    a = args->next();
7964    if (!a)
7965        return false;
7966    RefPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
7967    if (!point)
7968        return false;
7969    result->setFirstX(point.release());
7970
7971    // First Y.  It can be top, bottom, number or percent.
7972    a = args->next();
7973    if (!a)
7974        return false;
7975    point = parseDeprecatedGradientPoint(a, false);
7976    if (!point)
7977        return false;
7978    result->setFirstY(point.release());
7979
7980    // Comma after the first point.
7981    a = args->next();
7982    if (!isComma(a))
7983        return false;
7984
7985    // For radial gradients only, we now expect a numeric radius.
7986    if (gradientType == CSSDeprecatedRadialGradient) {
7987        a = args->next();
7988        if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
7989            return false;
7990        toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
7991
7992        // Comma after the first radius.
7993        a = args->next();
7994        if (!isComma(a))
7995            return false;
7996    }
7997
7998    // Next is the ending point for the gradient as an x, y pair.
7999    // Second X.  It can be left, right, number or percent.
8000    a = args->next();
8001    if (!a)
8002        return false;
8003    point = parseDeprecatedGradientPoint(a, true);
8004    if (!point)
8005        return false;
8006    result->setSecondX(point.release());
8007
8008    // Second Y.  It can be top, bottom, number or percent.
8009    a = args->next();
8010    if (!a)
8011        return false;
8012    point = parseDeprecatedGradientPoint(a, false);
8013    if (!point)
8014        return false;
8015    result->setSecondY(point.release());
8016
8017    // For radial gradients only, we now expect the second radius.
8018    if (gradientType == CSSDeprecatedRadialGradient) {
8019        // Comma after the second point.
8020        a = args->next();
8021        if (!isComma(a))
8022            return false;
8023
8024        a = args->next();
8025        if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
8026            return false;
8027        toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
8028    }
8029
8030    // We now will accept any number of stops (0 or more).
8031    a = args->next();
8032    while (a) {
8033        // Look for the comma before the next stop.
8034        if (!isComma(a))
8035            return false;
8036
8037        // Now examine the stop itself.
8038        a = args->next();
8039        if (!a)
8040            return false;
8041
8042        // The function name needs to be one of "from", "to", or "color-stop."
8043        CSSGradientColorStop stop;
8044        if (!parseDeprecatedGradientColorStop(this, a, stop))
8045            return false;
8046        result->addStop(stop);
8047
8048        // Advance
8049        a = args->next();
8050    }
8051
8052    gradient = result.release();
8053    return true;
8054}
8055
8056static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
8057{
8058    if (a->unit != CSSPrimitiveValue::CSS_IDENT)
8059        return 0;
8060
8061    switch (a->id) {
8062        case CSSValueLeft:
8063        case CSSValueRight:
8064            isHorizontal = true;
8065            break;
8066        case CSSValueTop:
8067        case CSSValueBottom:
8068            isHorizontal = false;
8069            break;
8070        default:
8071            return 0;
8072    }
8073    return cssValuePool().createIdentifierValue(a->id);
8074}
8075
8076static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSParser* p, CSSParserValue* value)
8077{
8078    CSSValueID id = value->id;
8079    if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
8080        return cssValuePool().createIdentifierValue(id);
8081
8082    return p->parseColor(value);
8083}
8084
8085bool CSSParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
8086{
8087    RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient);
8088
8089    // Walk the arguments.
8090    CSSParserValueList* args = valueList->current()->function->args.get();
8091    if (!args || !args->size())
8092        return false;
8093
8094    CSSParserValue* a = args->current();
8095    if (!a)
8096        return false;
8097
8098    bool expectComma = false;
8099    // Look for angle.
8100    if (validUnit(a, FAngle, CSSStrictMode)) {
8101        result->setAngle(createPrimitiveNumericValue(a));
8102
8103        args->next();
8104        expectComma = true;
8105    } else {
8106        // Look one or two optional keywords that indicate a side or corner.
8107        RefPtr<CSSPrimitiveValue> startX, startY;
8108
8109        RefPtr<CSSPrimitiveValue> location;
8110        bool isHorizontal = false;
8111        if ((location = valueFromSideKeyword(a, isHorizontal))) {
8112            if (isHorizontal)
8113                startX = location;
8114            else
8115                startY = location;
8116
8117            if ((a = args->next())) {
8118                if ((location = valueFromSideKeyword(a, isHorizontal))) {
8119                    if (isHorizontal) {
8120                        if (startX)
8121                            return false;
8122                        startX = location;
8123                    } else {
8124                        if (startY)
8125                            return false;
8126                        startY = location;
8127                    }
8128
8129                    args->next();
8130                }
8131            }
8132
8133            expectComma = true;
8134        }
8135
8136        if (!startX && !startY)
8137            startY = cssValuePool().createIdentifierValue(CSSValueTop);
8138
8139        result->setFirstX(startX.release());
8140        result->setFirstY(startY.release());
8141    }
8142
8143    if (!parseGradientColorStops(args, result.get(), expectComma))
8144        return false;
8145
8146    if (!result->stopCount())
8147        return false;
8148
8149    gradient = result.release();
8150    return true;
8151}
8152
8153bool CSSParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
8154{
8155    RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
8156
8157    // Walk the arguments.
8158    CSSParserValueList* args = valueList->current()->function->args.get();
8159    if (!args || !args->size())
8160        return false;
8161
8162    CSSParserValue* a = args->current();
8163    if (!a)
8164        return false;
8165
8166    bool expectComma = false;
8167
8168    // Optional background-position
8169    RefPtr<CSSValue> centerX;
8170    RefPtr<CSSValue> centerY;
8171    // parse2ValuesFillPosition advances the args next pointer.
8172    parse2ValuesFillPosition(args, centerX, centerY);
8173    a = args->current();
8174    if (!a)
8175        return false;
8176
8177    if (centerX || centerY) {
8178        // Comma
8179        if (!isComma(a))
8180            return false;
8181
8182        a = args->next();
8183        if (!a)
8184            return false;
8185    }
8186
8187    ASSERT(!centerX || centerX->isPrimitiveValue());
8188    ASSERT(!centerY || centerY->isPrimitiveValue());
8189
8190    result->setFirstX(toCSSPrimitiveValue(centerX.get()));
8191    result->setSecondX(toCSSPrimitiveValue(centerX.get()));
8192    // CSS3 radial gradients always share the same start and end point.
8193    result->setFirstY(toCSSPrimitiveValue(centerY.get()));
8194    result->setSecondY(toCSSPrimitiveValue(centerY.get()));
8195
8196    RefPtr<CSSPrimitiveValue> shapeValue;
8197    RefPtr<CSSPrimitiveValue> sizeValue;
8198
8199    // Optional shape and/or size in any order.
8200    for (int i = 0; i < 2; ++i) {
8201        if (a->unit != CSSPrimitiveValue::CSS_IDENT)
8202            break;
8203
8204        bool foundValue = false;
8205        switch (a->id) {
8206        case CSSValueCircle:
8207        case CSSValueEllipse:
8208            shapeValue = cssValuePool().createIdentifierValue(a->id);
8209            foundValue = true;
8210            break;
8211        case CSSValueClosestSide:
8212        case CSSValueClosestCorner:
8213        case CSSValueFarthestSide:
8214        case CSSValueFarthestCorner:
8215        case CSSValueContain:
8216        case CSSValueCover:
8217            sizeValue = cssValuePool().createIdentifierValue(a->id);
8218            foundValue = true;
8219            break;
8220        default:
8221            break;
8222        }
8223
8224        if (foundValue) {
8225            a = args->next();
8226            if (!a)
8227                return false;
8228
8229            expectComma = true;
8230        }
8231    }
8232
8233    result->setShape(shapeValue);
8234    result->setSizingBehavior(sizeValue);
8235
8236    // Or, two lengths or percentages
8237    RefPtr<CSSPrimitiveValue> horizontalSize;
8238    RefPtr<CSSPrimitiveValue> verticalSize;
8239
8240    if (!shapeValue && !sizeValue) {
8241        if (validUnit(a, FLength | FPercent)) {
8242            horizontalSize = createPrimitiveNumericValue(a);
8243            a = args->next();
8244            if (!a)
8245                return false;
8246
8247            expectComma = true;
8248        }
8249
8250        if (validUnit(a, FLength | FPercent)) {
8251            verticalSize = createPrimitiveNumericValue(a);
8252
8253            a = args->next();
8254            if (!a)
8255                return false;
8256            expectComma = true;
8257        }
8258    }
8259
8260    // Must have neither or both.
8261    if (!horizontalSize != !verticalSize)
8262        return false;
8263
8264    result->setEndHorizontalSize(horizontalSize);
8265    result->setEndVerticalSize(verticalSize);
8266
8267    if (!parseGradientColorStops(args, result.get(), expectComma))
8268        return false;
8269
8270    gradient = result.release();
8271    return true;
8272}
8273
8274bool CSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
8275{
8276    RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient);
8277
8278    CSSParserValueList* args = valueList->current()->function->args.get();
8279    if (!args || !args->size())
8280        return false;
8281
8282    CSSParserValue* a = args->current();
8283    if (!a)
8284        return false;
8285
8286    bool expectComma = false;
8287    // Look for angle.
8288    if (validUnit(a, FAngle, CSSStrictMode)) {
8289        result->setAngle(createPrimitiveNumericValue(a));
8290
8291        args->next();
8292        expectComma = true;
8293    } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) {
8294        // to [ [left | right] || [top | bottom] ]
8295        a = args->next();
8296        if (!a)
8297            return false;
8298
8299        RefPtr<CSSPrimitiveValue> endX, endY;
8300        RefPtr<CSSPrimitiveValue> location;
8301        bool isHorizontal = false;
8302
8303        location = valueFromSideKeyword(a, isHorizontal);
8304        if (!location)
8305            return false;
8306
8307        if (isHorizontal)
8308            endX = location;
8309        else
8310            endY = location;
8311
8312        a = args->next();
8313        if (!a)
8314            return false;
8315
8316        location = valueFromSideKeyword(a, isHorizontal);
8317        if (location) {
8318            if (isHorizontal) {
8319                if (endX)
8320                    return false;
8321                endX = location;
8322            } else {
8323                if (endY)
8324                    return false;
8325                endY = location;
8326            }
8327
8328            args->next();
8329        }
8330
8331        expectComma = true;
8332        result->setFirstX(endX.release());
8333        result->setFirstY(endY.release());
8334    }
8335
8336    if (!parseGradientColorStops(args, result.get(), expectComma))
8337        return false;
8338
8339    if (!result->stopCount())
8340        return false;
8341
8342    gradient = result.release();
8343    return true;
8344}
8345
8346bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
8347{
8348    RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
8349
8350    CSSParserValueList* args = valueList->current()->function->args.get();
8351    if (!args || !args->size())
8352        return false;
8353
8354    CSSParserValue* a = args->current();
8355    if (!a)
8356        return false;
8357
8358    bool expectComma = false;
8359
8360    RefPtr<CSSPrimitiveValue> shapeValue;
8361    RefPtr<CSSPrimitiveValue> sizeValue;
8362    RefPtr<CSSPrimitiveValue> horizontalSize;
8363    RefPtr<CSSPrimitiveValue> verticalSize;
8364
8365    // First part of grammar, the size/shape clause:
8366    // [ circle || <length> ] |
8367    // [ ellipse || [ <length> | <percentage> ]{2} ] |
8368    // [ [ circle | ellipse] || <size-keyword> ]
8369    for (int i = 0; i < 3; ++i) {
8370        if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
8371            bool badIdent = false;
8372            switch (a->id) {
8373            case CSSValueCircle:
8374            case CSSValueEllipse:
8375                if (shapeValue)
8376                    return false;
8377                shapeValue = cssValuePool().createIdentifierValue(a->id);
8378                break;
8379            case CSSValueClosestSide:
8380            case CSSValueClosestCorner:
8381            case CSSValueFarthestSide:
8382            case CSSValueFarthestCorner:
8383                if (sizeValue || horizontalSize)
8384                    return false;
8385                sizeValue = cssValuePool().createIdentifierValue(a->id);
8386                break;
8387            default:
8388                badIdent = true;
8389            }
8390
8391            if (badIdent)
8392                break;
8393
8394            a = args->next();
8395            if (!a)
8396                return false;
8397        } else if (validUnit(a, FLength | FPercent)) {
8398
8399            if (sizeValue || horizontalSize)
8400                return false;
8401            horizontalSize = createPrimitiveNumericValue(a);
8402
8403            a = args->next();
8404            if (!a)
8405                return false;
8406
8407            if (validUnit(a, FLength | FPercent)) {
8408                verticalSize = createPrimitiveNumericValue(a);
8409                ++i;
8410                a = args->next();
8411                if (!a)
8412                    return false;
8413            }
8414        } else
8415            break;
8416    }
8417
8418    // You can specify size as a keyword or a length/percentage, not both.
8419    if (sizeValue && horizontalSize)
8420        return false;
8421    // Circles must have 0 or 1 lengths.
8422    if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize)
8423        return false;
8424    // Ellipses must have 0 or 2 length/percentages.
8425    if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
8426        return false;
8427    // If there's only one size, it must be a length.
8428    if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
8429        return false;
8430
8431    result->setShape(shapeValue);
8432    result->setSizingBehavior(sizeValue);
8433    result->setEndHorizontalSize(horizontalSize);
8434    result->setEndVerticalSize(verticalSize);
8435
8436    // Second part of grammar, the center-position clause:
8437    // at <position>
8438    RefPtr<CSSValue> centerX;
8439    RefPtr<CSSValue> centerY;
8440    if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) {
8441        a = args->next();
8442        if (!a)
8443            return false;
8444
8445        parseFillPosition(args, centerX, centerY);
8446        if (!(centerX && centerY))
8447            return false;
8448
8449        a = args->current();
8450        if (!a)
8451            return false;
8452
8453        ASSERT(centerX->isPrimitiveValue());
8454        ASSERT(centerY->isPrimitiveValue());
8455        result->setFirstX(toCSSPrimitiveValue(centerX.get()));
8456        result->setFirstY(toCSSPrimitiveValue(centerY.get()));
8457        // Right now, CSS radial gradients have the same start and end centers.
8458        result->setSecondX(toCSSPrimitiveValue(centerX.get()));
8459        result->setSecondY(toCSSPrimitiveValue(centerY.get()));
8460    }
8461
8462    if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
8463        expectComma = true;
8464
8465    if (!parseGradientColorStops(args, result.get(), expectComma))
8466        return false;
8467
8468    gradient = result.release();
8469    return true;
8470}
8471
8472bool CSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
8473{
8474    CSSParserValue* a = valueList->current();
8475
8476    // Now look for color stops.
8477    while (a) {
8478        // Look for the comma before the next stop.
8479        if (expectComma) {
8480            if (!isComma(a))
8481                return false;
8482
8483            a = valueList->next();
8484            if (!a)
8485                return false;
8486        }
8487
8488        // <color-stop> = <color> [ <percentage> | <length> ]?
8489        CSSGradientColorStop stop;
8490        stop.m_color = parseGradientColorOrKeyword(this, a);
8491        if (!stop.m_color)
8492            return false;
8493
8494        a = valueList->next();
8495        if (a) {
8496            if (validUnit(a, FLength | FPercent)) {
8497                stop.m_position = createPrimitiveNumericValue(a);
8498                a = valueList->next();
8499            }
8500        }
8501
8502        gradient->addStop(stop);
8503        expectComma = true;
8504    }
8505
8506    // Must have 2 or more stops to be valid.
8507    return gradient->stopCount() >= 2;
8508}
8509
8510bool CSSParser::isGeneratedImageValue(CSSParserValue* val) const
8511{
8512    if (val->unit != CSSParserValue::Function)
8513        return false;
8514
8515    return equalIgnoringCase(val->function->name, "-webkit-gradient(")
8516        || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
8517        || equalIgnoringCase(val->function->name, "linear-gradient(")
8518        || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
8519        || equalIgnoringCase(val->function->name, "repeating-linear-gradient(")
8520        || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
8521        || equalIgnoringCase(val->function->name, "radial-gradient(")
8522        || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
8523        || equalIgnoringCase(val->function->name, "repeating-radial-gradient(")
8524        || equalIgnoringCase(val->function->name, "-webkit-canvas(")
8525        || equalIgnoringCase(val->function->name, "-webkit-cross-fade(")
8526        || equalIgnoringCase(val->function->name, "-webkit-filter(");
8527}
8528
8529bool CSSParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
8530{
8531    CSSParserValue* val = valueList->current();
8532
8533    if (val->unit != CSSParserValue::Function)
8534        return false;
8535
8536    if (equalIgnoringCase(val->function->name, "-webkit-gradient("))
8537        return parseDeprecatedGradient(valueList, value);
8538
8539    if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient("))
8540        return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
8541
8542    if (equalIgnoringCase(val->function->name, "linear-gradient("))
8543        return parseLinearGradient(valueList, value, NonRepeating);
8544
8545    if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient("))
8546        return parseDeprecatedLinearGradient(valueList, value, Repeating);
8547
8548    if (equalIgnoringCase(val->function->name, "repeating-linear-gradient("))
8549        return parseLinearGradient(valueList, value, Repeating);
8550
8551    if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient("))
8552        return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
8553
8554    if (equalIgnoringCase(val->function->name, "radial-gradient("))
8555        return parseRadialGradient(valueList, value, NonRepeating);
8556
8557    if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient("))
8558        return parseDeprecatedRadialGradient(valueList, value, Repeating);
8559
8560    if (equalIgnoringCase(val->function->name, "repeating-radial-gradient("))
8561        return parseRadialGradient(valueList, value, Repeating);
8562
8563    if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
8564        return parseCanvas(valueList, value);
8565
8566    if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
8567        return parseCrossfade(valueList, value);
8568
8569#if ENABLE(CSS_FILTERS)
8570    if (equalIgnoringCase(val->function->name, "-webkit-filter("))
8571        return parseFilterImage(valueList, value);
8572#endif
8573
8574    return false;
8575}
8576
8577#if ENABLE(CSS_FILTERS)
8578bool CSSParser::parseFilterImage(CSSParserValueList* valueList, RefPtr<CSSValue>& filter)
8579{
8580    RefPtr<CSSFilterImageValue> result;
8581
8582    // Walk the arguments.
8583    CSSParserValueList* args = valueList->current()->function->args.get();
8584    if (!args)
8585        return false;
8586    CSSParserValue* value = args->current();
8587    RefPtr<CSSValue> imageValue;
8588    RefPtr<CSSValue> filterValue;
8589
8590    if (!value)
8591        return false;
8592
8593    // The first argument is the image. It is a fill image.
8594    if (!parseFillImage(args, imageValue)) {
8595        if (value->unit == CSSPrimitiveValue::CSS_STRING)
8596            imageValue = CSSImageValue::create(completeURL(value->string));
8597        else
8598            return false;
8599    }
8600
8601    value = args->next();
8602
8603    // Skip a comma
8604    if (!isComma(value))
8605        return false;
8606    value = args->next();
8607
8608    if (!value || !parseFilter(args, filterValue))
8609        return false;
8610    value = args->next();
8611
8612    result = CSSFilterImageValue::create(imageValue.releaseNonNull(), filterValue.releaseNonNull());
8613
8614    filter = result;
8615
8616    return true;
8617}
8618#endif
8619
8620bool CSSParser::parseCrossfade(CSSParserValueList* valueList, RefPtr<CSSValue>& crossfade)
8621{
8622    RefPtr<CSSCrossfadeValue> result;
8623
8624    // Walk the arguments.
8625    CSSParserValueList* args = valueList->current()->function->args.get();
8626    if (!args || args->size() != 5)
8627        return false;
8628    CSSParserValue* a = args->current();
8629    RefPtr<CSSValue> fromImageValue;
8630    RefPtr<CSSValue> toImageValue;
8631
8632    // The first argument is the "from" image. It is a fill image.
8633    if (!a || !parseFillImage(args, fromImageValue))
8634        return false;
8635    a = args->next();
8636
8637    // Skip a comma
8638    if (!isComma(a))
8639        return false;
8640    a = args->next();
8641
8642    // The second argument is the "to" image. It is a fill image.
8643    if (!a || !parseFillImage(args, toImageValue))
8644        return false;
8645    a = args->next();
8646
8647    // Skip a comma
8648    if (!isComma(a))
8649        return false;
8650    a = args->next();
8651
8652    // The third argument is the crossfade value. It is a percentage or a fractional number.
8653    RefPtr<CSSPrimitiveValue> percentage;
8654    if (!a)
8655        return false;
8656
8657    if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
8658        percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
8659    else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
8660        percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
8661    else
8662        return false;
8663
8664    result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
8665    result->setPercentage(percentage);
8666
8667    crossfade = result;
8668
8669    return true;
8670}
8671
8672bool CSSParser::parseCanvas(CSSParserValueList* valueList, RefPtr<CSSValue>& canvas)
8673{
8674    // Walk the arguments.
8675    CSSParserValueList* args = valueList->current()->function->args.get();
8676    if (!args || args->size() != 1)
8677        return false;
8678
8679    // The first argument is the canvas name.  It is an identifier.
8680    CSSParserValue* value = args->current();
8681    if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
8682        return false;
8683
8684    canvas = CSSCanvasValue::create(value->string);
8685    return true;
8686}
8687
8688#if ENABLE(CSS_IMAGE_RESOLUTION)
8689PassRefPtr<CSSValue> CSSParser::parseImageResolution()
8690{
8691    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8692    bool haveResolution = false;
8693    bool haveFromImage = false;
8694    bool haveSnap = false;
8695
8696    CSSParserValue* value = m_valueList->current();
8697    while (value) {
8698        if (!haveFromImage && value->id == CSSValueFromImage) {
8699            list->append(cssValuePool().createIdentifierValue(value->id));
8700            haveFromImage = true;
8701        } else if (!haveSnap && value->id == CSSValueSnap) {
8702            list->append(cssValuePool().createIdentifierValue(value->id));
8703            haveSnap = true;
8704        } else if (!haveResolution && validUnit(value, FResolution | FNonNeg) && value->fValue > 0) {
8705            list->append(createPrimitiveNumericValue(value));
8706            haveResolution = true;
8707        } else
8708            return 0;
8709        value = m_valueList->next();
8710    }
8711    if (!list->length())
8712        return 0;
8713    if (!haveFromImage && !haveResolution)
8714        return 0;
8715    return list.release();
8716}
8717#endif
8718
8719#if ENABLE(CSS_IMAGE_SET)
8720PassRefPtr<CSSValue> CSSParser::parseImageSet()
8721{
8722    CSSParserValue* value = m_valueList->current();
8723    ASSERT(value->unit == CSSParserValue::Function);
8724
8725    CSSParserValueList* functionArgs = value->function->args.get();
8726    if (!functionArgs || !functionArgs->size() || !functionArgs->current())
8727        return 0;
8728
8729    RefPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
8730    CSSParserValue* arg = functionArgs->current();
8731    while (arg) {
8732        if (arg->unit != CSSPrimitiveValue::CSS_URI)
8733            return 0;
8734
8735        imageSet->append(CSSImageValue::create(completeURL(arg->string)));
8736        arg = functionArgs->next();
8737        if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
8738            return 0;
8739
8740        double imageScaleFactor = 0;
8741        const String& string = arg->string;
8742        unsigned length = string.length();
8743        if (!length)
8744            return 0;
8745        if (string.is8Bit()) {
8746            const LChar* start = string.characters8();
8747            parseDouble(start, start + length, 'x', imageScaleFactor);
8748        } else {
8749            const UChar* start = string.characters16();
8750            parseDouble(start, start + length, 'x', imageScaleFactor);
8751        }
8752        if (imageScaleFactor <= 0)
8753            return 0;
8754        imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER));
8755
8756        // If there are no more arguments, we're done.
8757        arg = functionArgs->next();
8758        if (!arg)
8759            break;
8760
8761        // If there are more arguments, they should be after a comma.
8762        if (!isComma(arg))
8763            return 0;
8764
8765        // Skip the comma and move on to the next argument.
8766        arg = functionArgs->next();
8767    }
8768
8769    return imageSet.release();
8770}
8771#endif
8772
8773class TransformOperationInfo {
8774public:
8775    TransformOperationInfo(const CSSParserString& name)
8776        : m_type(WebKitCSSTransformValue::UnknownTransformOperation)
8777        , m_argCount(1)
8778        , m_allowSingleArgument(false)
8779        , m_unit(CSSParser::FUnknown)
8780    {
8781        const UChar* characters;
8782        unsigned nameLength = name.length();
8783
8784        const unsigned longestNameLength = 12;
8785        UChar characterBuffer[longestNameLength];
8786        if (name.is8Bit()) {
8787            unsigned length = std::min(longestNameLength, nameLength);
8788            const LChar* characters8 = name.characters8();
8789            for (unsigned i = 0; i < length; ++i)
8790                characterBuffer[i] = characters8[i];
8791            characters = characterBuffer;
8792        } else
8793            characters = name.characters16();
8794
8795        switch (nameLength) {
8796        case 5:
8797            // Valid name: skew(.
8798            if (((characters[0] == 's') || (characters[0] == 'S'))
8799                & ((characters[1] == 'k') || (characters[1] == 'K'))
8800                & ((characters[2] == 'e') || (characters[2] == 'E'))
8801                & ((characters[3] == 'w') || (characters[3] == 'W'))
8802                & (characters[4] == '(')) {
8803                m_unit = CSSParser::FAngle;
8804                m_type = WebKitCSSTransformValue::SkewTransformOperation;
8805                m_allowSingleArgument = true;
8806                m_argCount = 3;
8807            }
8808            break;
8809        case 6:
8810            // Valid names: skewx(, skewy(, scale(.
8811            if ((characters[1] == 'c') || (characters[1] == 'C')) {
8812                if (((characters[0] == 's') || (characters[0] == 'S'))
8813                    & ((characters[2] == 'a') || (characters[2] == 'A'))
8814                    & ((characters[3] == 'l') || (characters[3] == 'L'))
8815                    & ((characters[4] == 'e') || (characters[4] == 'E'))
8816                    & (characters[5] == '(')) {
8817                    m_unit = CSSParser::FNumber;
8818                    m_type = WebKitCSSTransformValue::ScaleTransformOperation;
8819                    m_allowSingleArgument = true;
8820                    m_argCount = 3;
8821                }
8822            } else if (((characters[0] == 's') || (characters[0] == 'S'))
8823                       & ((characters[1] == 'k') || (characters[1] == 'K'))
8824                       & ((characters[2] == 'e') || (characters[2] == 'E'))
8825                       & ((characters[3] == 'w') || (characters[3] == 'W'))
8826                       & (characters[5] == '(')) {
8827                if ((characters[4] == 'x') || (characters[4] == 'X')) {
8828                    m_unit = CSSParser::FAngle;
8829                    m_type = WebKitCSSTransformValue::SkewXTransformOperation;
8830                } else if ((characters[4] == 'y') || (characters[4] == 'Y')) {
8831                    m_unit = CSSParser::FAngle;
8832                    m_type = WebKitCSSTransformValue::SkewYTransformOperation;
8833                }
8834            }
8835            break;
8836        case 7:
8837            // Valid names: matrix(, rotate(, scalex(, scaley(, scalez(.
8838            if ((characters[0] == 'm') || (characters[0] == 'M')) {
8839                if (((characters[1] == 'a') || (characters[1] == 'A'))
8840                    & ((characters[2] == 't') || (characters[2] == 'T'))
8841                    & ((characters[3] == 'r') || (characters[3] == 'R'))
8842                    & ((characters[4] == 'i') || (characters[4] == 'I'))
8843                    & ((characters[5] == 'x') || (characters[5] == 'X'))
8844                    & (characters[6] == '(')) {
8845                    m_unit = CSSParser::FNumber;
8846                    m_type = WebKitCSSTransformValue::MatrixTransformOperation;
8847                    m_argCount = 11;
8848                }
8849            } else if ((characters[0] == 'r') || (characters[0] == 'R')) {
8850                if (((characters[1] == 'o') || (characters[1] == 'O'))
8851                    & ((characters[2] == 't') || (characters[2] == 'T'))
8852                    & ((characters[3] == 'a') || (characters[3] == 'A'))
8853                    & ((characters[4] == 't') || (characters[4] == 'T'))
8854                    & ((characters[5] == 'e') || (characters[5] == 'E'))
8855                    & (characters[6] == '(')) {
8856                    m_unit = CSSParser::FAngle;
8857                    m_type = WebKitCSSTransformValue::RotateTransformOperation;
8858                }
8859            } else if (((characters[0] == 's') || (characters[0] == 'S'))
8860                       & ((characters[1] == 'c') || (characters[1] == 'C'))
8861                       & ((characters[2] == 'a') || (characters[2] == 'A'))
8862                       & ((characters[3] == 'l') || (characters[3] == 'L'))
8863                       & ((characters[4] == 'e') || (characters[4] == 'E'))
8864                       & (characters[6] == '(')) {
8865                if ((characters[5] == 'x') || (characters[5] == 'X')) {
8866                    m_unit = CSSParser::FNumber;
8867                    m_type = WebKitCSSTransformValue::ScaleXTransformOperation;
8868                } else if ((characters[5] == 'y') || (characters[5] == 'Y')) {
8869                    m_unit = CSSParser::FNumber;
8870                    m_type = WebKitCSSTransformValue::ScaleYTransformOperation;
8871                } else if ((characters[5] == 'z') || (characters[5] == 'Z')) {
8872                    m_unit = CSSParser::FNumber;
8873                    m_type = WebKitCSSTransformValue::ScaleZTransformOperation;
8874                }
8875            }
8876            break;
8877        case 8:
8878            // Valid names: rotatex(, rotatey(, rotatez(, scale3d(.
8879            if ((characters[0] == 's') || (characters[0] == 'S')) {
8880                if (((characters[1] == 'c') || (characters[1] == 'C'))
8881                    & ((characters[2] == 'a') || (characters[2] == 'A'))
8882                    & ((characters[3] == 'l') || (characters[3] == 'L'))
8883                    & ((characters[4] == 'e') || (characters[4] == 'E'))
8884                    & (characters[5] == '3')
8885                    & ((characters[6] == 'd') || (characters[6] == 'D'))
8886                    & (characters[7] == '(')) {
8887                    m_unit = CSSParser::FNumber;
8888                    m_type = WebKitCSSTransformValue::Scale3DTransformOperation;
8889                    m_argCount = 5;
8890                }
8891            } else if (((characters[0] == 'r') || (characters[0] == 'R'))
8892                       & ((characters[1] == 'o') || (characters[1] == 'O'))
8893                       & ((characters[2] == 't') || (characters[2] == 'T'))
8894                       & ((characters[3] == 'a') || (characters[3] == 'A'))
8895                       & ((characters[4] == 't') || (characters[4] == 'T'))
8896                       & ((characters[5] == 'e') || (characters[5] == 'E'))
8897                       & (characters[7] == '(')) {
8898                if ((characters[6] == 'x') || (characters[6] == 'X')) {
8899                    m_unit = CSSParser::FAngle;
8900                    m_type = WebKitCSSTransformValue::RotateXTransformOperation;
8901                } else if ((characters[6] == 'y') || (characters[6] == 'Y')) {
8902                    m_unit = CSSParser::FAngle;
8903                    m_type = WebKitCSSTransformValue::RotateYTransformOperation;
8904                } else if ((characters[6] == 'z') || (characters[6] == 'Z')) {
8905                    m_unit = CSSParser::FAngle;
8906                    m_type = WebKitCSSTransformValue::RotateZTransformOperation;
8907                }
8908            }
8909            break;
8910        case 9:
8911            // Valid names: matrix3d(, rotate3d(.
8912            if ((characters[0] == 'm') || (characters[0] == 'M')) {
8913                if (((characters[1] == 'a') || (characters[1] == 'A'))
8914                    & ((characters[2] == 't') || (characters[2] == 'T'))
8915                    & ((characters[3] == 'r') || (characters[3] == 'R'))
8916                    & ((characters[4] == 'i') || (characters[4] == 'I'))
8917                    & ((characters[5] == 'x') || (characters[5] == 'X'))
8918                    & (characters[6] == '3')
8919                    & ((characters[7] == 'd') || (characters[7] == 'D'))
8920                    & (characters[8] == '(')) {
8921                    m_unit = CSSParser::FNumber;
8922                    m_type = WebKitCSSTransformValue::Matrix3DTransformOperation;
8923                    m_argCount = 31;
8924                }
8925            } else if (((characters[0] == 'r') || (characters[0] == 'R'))
8926                       & ((characters[1] == 'o') || (characters[1] == 'O'))
8927                       & ((characters[2] == 't') || (characters[2] == 'T'))
8928                       & ((characters[3] == 'a') || (characters[3] == 'A'))
8929                       & ((characters[4] == 't') || (characters[4] == 'T'))
8930                       & ((characters[5] == 'e') || (characters[5] == 'E'))
8931                       & (characters[6] == '3')
8932                       & ((characters[7] == 'd') || (characters[7] == 'D'))
8933                       & (characters[8] == '(')) {
8934                m_unit = CSSParser::FNumber;
8935                m_type = WebKitCSSTransformValue::Rotate3DTransformOperation;
8936                m_argCount = 7;
8937            }
8938            break;
8939        case 10:
8940            // Valid name: translate(.
8941            if (((characters[0] == 't') || (characters[0] == 'T'))
8942                & ((characters[1] == 'r') || (characters[1] == 'R'))
8943                & ((characters[2] == 'a') || (characters[2] == 'A'))
8944                & ((characters[3] == 'n') || (characters[3] == 'N'))
8945                & ((characters[4] == 's') || (characters[4] == 'S'))
8946                & ((characters[5] == 'l') || (characters[5] == 'L'))
8947                & ((characters[6] == 'a') || (characters[6] == 'A'))
8948                & ((characters[7] == 't') || (characters[7] == 'T'))
8949                & ((characters[8] == 'e') || (characters[8] == 'E'))
8950                & (characters[9] == '(')) {
8951                m_unit = CSSParser::FLength | CSSParser::FPercent;
8952                m_type = WebKitCSSTransformValue::TranslateTransformOperation;
8953                m_allowSingleArgument = true;
8954                m_argCount = 3;
8955            }
8956            break;
8957        case 11:
8958            // Valid names: translatex(, translatey(, translatez(.
8959            if (((characters[0] == 't') || (characters[0] == 'T'))
8960                & ((characters[1] == 'r') || (characters[1] == 'R'))
8961                & ((characters[2] == 'a') || (characters[2] == 'A'))
8962                & ((characters[3] == 'n') || (characters[3] == 'N'))
8963                & ((characters[4] == 's') || (characters[4] == 'S'))
8964                & ((characters[5] == 'l') || (characters[5] == 'L'))
8965                & ((characters[6] == 'a') || (characters[6] == 'A'))
8966                & ((characters[7] == 't') || (characters[7] == 'T'))
8967                & ((characters[8] == 'e') || (characters[8] == 'E'))
8968                & (characters[10] == '(')) {
8969                if ((characters[9] == 'x') || (characters[9] == 'X')) {
8970                    m_unit = CSSParser::FLength | CSSParser::FPercent;
8971                    m_type = WebKitCSSTransformValue::TranslateXTransformOperation;
8972                } else if ((characters[9] == 'y') || (characters[9] == 'Y')) {
8973                    m_unit = CSSParser::FLength | CSSParser::FPercent;
8974                    m_type = WebKitCSSTransformValue::TranslateYTransformOperation;
8975                } else if ((characters[9] == 'z') || (characters[9] == 'Z')) {
8976                    m_unit = CSSParser::FLength | CSSParser::FPercent;
8977                    m_type = WebKitCSSTransformValue::TranslateZTransformOperation;
8978                }
8979            }
8980            break;
8981        case 12:
8982            // Valid names: perspective(, translate3d(.
8983            if ((characters[0] == 'p') || (characters[0] == 'P')) {
8984                if (((characters[1] == 'e') || (characters[1] == 'E'))
8985                    & ((characters[2] == 'r') || (characters[2] == 'R'))
8986                    & ((characters[3] == 's') || (characters[3] == 'S'))
8987                    & ((characters[4] == 'p') || (characters[4] == 'P'))
8988                    & ((characters[5] == 'e') || (characters[5] == 'E'))
8989                    & ((characters[6] == 'c') || (characters[6] == 'C'))
8990                    & ((characters[7] == 't') || (characters[7] == 'T'))
8991                    & ((characters[8] == 'i') || (characters[8] == 'I'))
8992                    & ((characters[9] == 'v') || (characters[9] == 'V'))
8993                    & ((characters[10] == 'e') || (characters[10] == 'E'))
8994                    & (characters[11] == '(')) {
8995                    m_unit = CSSParser::FNumber;
8996                    m_type = WebKitCSSTransformValue::PerspectiveTransformOperation;
8997                }
8998            } else if (((characters[0] == 't') || (characters[0] == 'T'))
8999                       & ((characters[1] == 'r') || (characters[1] == 'R'))
9000                       & ((characters[2] == 'a') || (characters[2] == 'A'))
9001                       & ((characters[3] == 'n') || (characters[3] == 'N'))
9002                       & ((characters[4] == 's') || (characters[4] == 'S'))
9003                       & ((characters[5] == 'l') || (characters[5] == 'L'))
9004                       & ((characters[6] == 'a') || (characters[6] == 'A'))
9005                       & ((characters[7] == 't') || (characters[7] == 'T'))
9006                       & ((characters[8] == 'e') || (characters[8] == 'E'))
9007                       & (characters[9] == '3')
9008                       & ((characters[10] == 'd') || (characters[10] == 'D'))
9009                       & (characters[11] == '(')) {
9010                m_unit = CSSParser::FLength | CSSParser::FPercent;
9011                m_type = WebKitCSSTransformValue::Translate3DTransformOperation;
9012                m_argCount = 5;
9013            }
9014            break;
9015        } // end switch ()
9016    }
9017
9018    WebKitCSSTransformValue::TransformOperationType type() const { return m_type; }
9019    unsigned argCount() const { return m_argCount; }
9020    CSSParser::Units unit() const { return m_unit; }
9021
9022    bool unknown() const { return m_type == WebKitCSSTransformValue::UnknownTransformOperation; }
9023    bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
9024
9025private:
9026    WebKitCSSTransformValue::TransformOperationType m_type;
9027    unsigned m_argCount;
9028    bool m_allowSingleArgument;
9029    CSSParser::Units m_unit;
9030};
9031
9032PassRefPtr<CSSValueList> CSSParser::parseTransform()
9033{
9034    if (!m_valueList)
9035        return 0;
9036
9037    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9038    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9039        RefPtr<CSSValue> parsedTransformValue = parseTransformValue(value);
9040        if (!parsedTransformValue)
9041            return 0;
9042
9043        list->append(parsedTransformValue.release());
9044    }
9045
9046    return list.release();
9047}
9048
9049PassRefPtr<CSSValue> CSSParser::parseTransformValue(CSSParserValue *value)
9050{
9051    if (value->unit != CSSParserValue::Function || !value->function)
9052        return 0;
9053
9054    // Every primitive requires at least one argument.
9055    CSSParserValueList* args = value->function->args.get();
9056    if (!args)
9057        return 0;
9058
9059    // See if the specified primitive is one we understand.
9060    TransformOperationInfo info(value->function->name);
9061    if (info.unknown())
9062        return 0;
9063
9064    if (!info.hasCorrectArgCount(args->size()))
9065        return 0;
9066
9067    // The transform is a list of functional primitives that specify transform operations.
9068    // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation.
9069
9070    // Create the new WebKitCSSTransformValue for this operation and add it to our list.
9071    RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(info.type());
9072
9073    // Snag our values.
9074    CSSParserValue* a = args->current();
9075    unsigned argNumber = 0;
9076    while (a) {
9077        CSSParser::Units unit = info.unit();
9078
9079        if (info.type() == WebKitCSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
9080            // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
9081            if (!validUnit(a, FAngle, CSSStrictMode))
9082                return 0;
9083        } else if (info.type() == WebKitCSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
9084            // 3rd param of translate3d() cannot be a percentage
9085            if (!validUnit(a, FLength, CSSStrictMode))
9086                return 0;
9087        } else if (info.type() == WebKitCSSTransformValue::TranslateZTransformOperation && !argNumber) {
9088            // 1st param of translateZ() cannot be a percentage
9089            if (!validUnit(a, FLength, CSSStrictMode))
9090                return 0;
9091        } else if (info.type() == WebKitCSSTransformValue::PerspectiveTransformOperation && !argNumber) {
9092            // 1st param of perspective() must be a non-negative number (deprecated) or length.
9093            if (!validUnit(a, FNumber | FLength | FNonNeg, CSSStrictMode))
9094                return 0;
9095        } else if (!validUnit(a, unit, CSSStrictMode))
9096            return 0;
9097
9098        // Add the value to the current transform operation.
9099        transformValue->append(createPrimitiveNumericValue(a));
9100
9101        a = args->next();
9102        if (!a)
9103            break;
9104        if (a->unit != CSSParserValue::Operator || a->iValue != ',')
9105            return 0;
9106        a = args->next();
9107
9108        argNumber++;
9109    }
9110
9111    return transformValue.release();
9112}
9113
9114bool CSSParser::isBlendMode(CSSValueID valueID)
9115{
9116    return (valueID >= CSSValueMultiply && valueID <= CSSValueLuminosity)
9117        || valueID == CSSValueNormal
9118        || valueID == CSSValueOverlay;
9119}
9120
9121bool CSSParser::isCompositeOperator(CSSValueID valueID)
9122{
9123    // FIXME: Add CSSValueDestination and CSSValueLighter when the Compositing spec updates.
9124    return valueID >= CSSValueClear && valueID <= CSSValueXor;
9125}
9126
9127#if ENABLE(CSS_FILTERS)
9128
9129static void filterInfoForName(const CSSParserString& name, WebKitCSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
9130{
9131    if (equalIgnoringCase(name, "grayscale("))
9132        filterType = WebKitCSSFilterValue::GrayscaleFilterOperation;
9133    else if (equalIgnoringCase(name, "sepia("))
9134        filterType = WebKitCSSFilterValue::SepiaFilterOperation;
9135    else if (equalIgnoringCase(name, "saturate("))
9136        filterType = WebKitCSSFilterValue::SaturateFilterOperation;
9137    else if (equalIgnoringCase(name, "hue-rotate("))
9138        filterType = WebKitCSSFilterValue::HueRotateFilterOperation;
9139    else if (equalIgnoringCase(name, "invert("))
9140        filterType = WebKitCSSFilterValue::InvertFilterOperation;
9141    else if (equalIgnoringCase(name, "opacity("))
9142        filterType = WebKitCSSFilterValue::OpacityFilterOperation;
9143    else if (equalIgnoringCase(name, "brightness("))
9144        filterType = WebKitCSSFilterValue::BrightnessFilterOperation;
9145    else if (equalIgnoringCase(name, "contrast("))
9146        filterType = WebKitCSSFilterValue::ContrastFilterOperation;
9147    else if (equalIgnoringCase(name, "blur("))
9148        filterType = WebKitCSSFilterValue::BlurFilterOperation;
9149    else if (equalIgnoringCase(name, "drop-shadow(")) {
9150        filterType = WebKitCSSFilterValue::DropShadowFilterOperation;
9151        maximumArgumentCount = 4;  // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
9152    }
9153}
9154
9155PassRefPtr<WebKitCSSFilterValue> CSSParser::parseBuiltinFilterArguments(CSSParserValueList* args, WebKitCSSFilterValue::FilterOperationType filterType)
9156{
9157    RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(filterType);
9158    ASSERT(args);
9159
9160    switch (filterType) {
9161    case WebKitCSSFilterValue::GrayscaleFilterOperation:
9162    case WebKitCSSFilterValue::SepiaFilterOperation:
9163    case WebKitCSSFilterValue::SaturateFilterOperation:
9164    case WebKitCSSFilterValue::InvertFilterOperation:
9165    case WebKitCSSFilterValue::OpacityFilterOperation:
9166    case WebKitCSSFilterValue::ContrastFilterOperation: {
9167        // One optional argument, 0-1 or 0%-100%, if missing use 100%.
9168        if (args->size() > 1)
9169            return 0;
9170
9171        if (args->size()) {
9172            CSSParserValue* value = args->current();
9173            if (!validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode))
9174                return 0;
9175
9176            double amount = value->fValue;
9177
9178            // Saturate and Contrast allow values over 100%.
9179            if (filterType != WebKitCSSFilterValue::SaturateFilterOperation
9180                && filterType != WebKitCSSFilterValue::ContrastFilterOperation) {
9181                double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
9182                if (amount > maxAllowed)
9183                    return 0;
9184            }
9185
9186            filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
9187        }
9188        break;
9189    }
9190    case WebKitCSSFilterValue::BrightnessFilterOperation: {
9191        // One optional argument, if missing use 100%.
9192        if (args->size() > 1)
9193            return 0;
9194
9195        if (args->size()) {
9196            CSSParserValue* value = args->current();
9197            if (!validUnit(value, FNumber | FPercent, CSSStrictMode))
9198                return 0;
9199
9200            filterValue->append(cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
9201        }
9202        break;
9203    }
9204    case WebKitCSSFilterValue::HueRotateFilterOperation: {
9205        // hue-rotate() takes one optional angle.
9206        if (args->size() > 1)
9207            return 0;
9208
9209        if (args->size()) {
9210            CSSParserValue* argument = args->current();
9211            if (!validUnit(argument, FAngle, CSSStrictMode))
9212                return 0;
9213
9214            filterValue->append(createPrimitiveNumericValue(argument));
9215        }
9216        break;
9217    }
9218    case WebKitCSSFilterValue::BlurFilterOperation: {
9219        // Blur takes a single length. Zero parameters are allowed.
9220        if (args->size() > 1)
9221            return 0;
9222
9223        if (args->size()) {
9224            CSSParserValue* argument = args->current();
9225            if (!validUnit(argument, FLength | FNonNeg, CSSStrictMode))
9226                return 0;
9227
9228            filterValue->append(createPrimitiveNumericValue(argument));
9229        }
9230        break;
9231    }
9232    case WebKitCSSFilterValue::DropShadowFilterOperation: {
9233        // drop-shadow() takes a single shadow.
9234        RefPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter);
9235        if (!shadowValueList || shadowValueList->length() != 1)
9236            return 0;
9237
9238        filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0));
9239        break;
9240    }
9241    default:
9242        ASSERT_NOT_REACHED();
9243    }
9244    return filterValue.release();
9245}
9246
9247bool CSSParser::parseFilter(CSSParserValueList* valueList, RefPtr<CSSValue>& result)
9248{
9249    if (!valueList)
9250        return false;
9251
9252    // The filter is a list of functional primitives that specify individual operations.
9253    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9254    for (auto value = valueList->current(); value; value = valueList->next()) {
9255        if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function))
9256            return false;
9257
9258        WebKitCSSFilterValue::FilterOperationType filterType = WebKitCSSFilterValue::UnknownFilterOperation;
9259
9260        // See if the specified primitive is one we understand.
9261        if (value->unit == CSSPrimitiveValue::CSS_URI) {
9262            RefPtr<WebKitCSSFilterValue> referenceFilterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::ReferenceFilterOperation);
9263            referenceFilterValue->append(CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI));
9264            list->append(referenceFilterValue.release());
9265        } else {
9266            const CSSParserString name = value->function->name;
9267            unsigned maximumArgumentCount = 1;
9268
9269            filterInfoForName(name, filterType, maximumArgumentCount);
9270
9271            if (filterType == WebKitCSSFilterValue::UnknownFilterOperation)
9272                return false;
9273
9274            CSSParserValueList* args = value->function->args.get();
9275            if (!args)
9276                return false;
9277
9278            RefPtr<WebKitCSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType);
9279            if (!filterValue)
9280                return false;
9281
9282            list->append(filterValue.release());
9283        }
9284    }
9285
9286    result = list;
9287
9288    return true;
9289}
9290#endif
9291
9292#if ENABLE(CSS_REGIONS)
9293static bool validFlowName(const String& flowName)
9294{
9295    return !(equalIgnoringCase(flowName, "auto")
9296            || equalIgnoringCase(flowName, "default")
9297            || equalIgnoringCase(flowName, "inherit")
9298            || equalIgnoringCase(flowName, "initial")
9299            || equalIgnoringCase(flowName, "none"));
9300}
9301#endif
9302
9303bool CSSParser::cssRegionsEnabled() const
9304{
9305    return m_context.isCSSRegionsEnabled;
9306}
9307
9308bool CSSParser::cssCompositingEnabled() const
9309{
9310    return m_context.isCSSCompositingEnabled;
9311}
9312
9313#if ENABLE(CSS_REGIONS)
9314
9315// none | <ident>
9316bool CSSParser::parseFlowThread(CSSPropertyID propId, bool important)
9317{
9318    ASSERT(propId == CSSPropertyWebkitFlowInto);
9319    ASSERT(cssRegionsEnabled());
9320
9321    if (m_valueList->size() != 1)
9322        return false;
9323
9324    CSSParserValue* value = m_valueList->current();
9325    if (!value)
9326        return false;
9327
9328    if (value->unit != CSSPrimitiveValue::CSS_IDENT)
9329        return false;
9330
9331    if (value->id == CSSValueNone) {
9332        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
9333        return true;
9334    }
9335
9336    String inputProperty = String(value->string);
9337    if (!inputProperty.isEmpty()) {
9338        if (!validFlowName(inputProperty))
9339            return false;
9340        addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
9341    } else
9342        addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
9343
9344    return true;
9345}
9346
9347// -webkit-flow-from: none | <ident>
9348bool CSSParser::parseRegionThread(CSSPropertyID propId, bool important)
9349{
9350    ASSERT(propId == CSSPropertyWebkitFlowFrom);
9351    ASSERT(cssRegionsEnabled());
9352
9353    if (m_valueList->size() != 1)
9354        return false;
9355
9356    CSSParserValue* value = m_valueList->current();
9357    if (!value)
9358        return false;
9359
9360    if (value->unit != CSSPrimitiveValue::CSS_IDENT)
9361        return false;
9362
9363    if (value->id == CSSValueNone)
9364        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
9365    else {
9366        String inputProperty = String(value->string);
9367        if (!inputProperty.isEmpty()) {
9368            if (!validFlowName(inputProperty))
9369                return false;
9370            addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
9371        } else
9372            addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
9373    }
9374
9375    return true;
9376}
9377#endif
9378
9379bool CSSParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
9380{
9381    propId1 = propId;
9382    propId2 = propId;
9383    propId3 = propId;
9384    if (propId == CSSPropertyWebkitTransformOrigin) {
9385        propId1 = CSSPropertyWebkitTransformOriginX;
9386        propId2 = CSSPropertyWebkitTransformOriginY;
9387        propId3 = CSSPropertyWebkitTransformOriginZ;
9388    }
9389
9390    switch (propId) {
9391        case CSSPropertyWebkitTransformOrigin:
9392            if (!parseTransformOriginShorthand(value, value2, value3))
9393                return false;
9394            // parseTransformOriginShorthand advances the m_valueList pointer
9395            break;
9396        case CSSPropertyWebkitTransformOriginX: {
9397            value = parseFillPositionX(m_valueList.get());
9398            if (value)
9399                m_valueList->next();
9400            break;
9401        }
9402        case CSSPropertyWebkitTransformOriginY: {
9403            value = parseFillPositionY(m_valueList.get());
9404            if (value)
9405                m_valueList->next();
9406            break;
9407        }
9408        case CSSPropertyWebkitTransformOriginZ: {
9409            if (validUnit(m_valueList->current(), FLength))
9410                value = createPrimitiveNumericValue(m_valueList->current());
9411            if (value)
9412                m_valueList->next();
9413            break;
9414        }
9415        default:
9416            ASSERT_NOT_REACHED();
9417            return false;
9418    }
9419
9420    return value;
9421}
9422
9423bool CSSParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2)
9424{
9425    propId1 = propId;
9426    propId2 = propId;
9427    if (propId == CSSPropertyWebkitPerspectiveOrigin) {
9428        propId1 = CSSPropertyWebkitPerspectiveOriginX;
9429        propId2 = CSSPropertyWebkitPerspectiveOriginY;
9430    }
9431
9432    switch (propId) {
9433        case CSSPropertyWebkitPerspectiveOrigin:
9434            if (m_valueList->size() > 2)
9435                return false;
9436            parse2ValuesFillPosition(m_valueList.get(), value, value2);
9437            break;
9438        case CSSPropertyWebkitPerspectiveOriginX: {
9439            value = parseFillPositionX(m_valueList.get());
9440            if (value)
9441                m_valueList->next();
9442            break;
9443        }
9444        case CSSPropertyWebkitPerspectiveOriginY: {
9445            value = parseFillPositionY(m_valueList.get());
9446            if (value)
9447                m_valueList->next();
9448            break;
9449        }
9450        default:
9451            ASSERT_NOT_REACHED();
9452            return false;
9453    }
9454
9455    return value;
9456}
9457
9458void CSSParser::addTextDecorationProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important)
9459{
9460    // The text-decoration-line property takes priority over text-decoration, unless the latter has important priority set.
9461    if (propId == CSSPropertyTextDecoration && !important && !inShorthand()) {
9462        for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
9463            if (m_parsedProperties[i].id() == CSSPropertyWebkitTextDecorationLine)
9464                return;
9465        }
9466    }
9467    addProperty(propId, value, important);
9468}
9469
9470bool CSSParser::parseTextDecoration(CSSPropertyID propId, bool important)
9471{
9472    CSSParserValue* value = m_valueList->current();
9473    if (value && value->id == CSSValueNone) {
9474        addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
9475        m_valueList->next();
9476        return true;
9477    }
9478
9479    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9480    bool isValid = true;
9481    while (isValid && value) {
9482        switch (value->id) {
9483        case CSSValueBlink:
9484        case CSSValueLineThrough:
9485        case CSSValueOverline:
9486        case CSSValueUnderline:
9487#if ENABLE(LETTERPRESS)
9488        case CSSValueWebkitLetterpress:
9489#endif
9490            list->append(cssValuePool().createIdentifierValue(value->id));
9491            break;
9492        default:
9493            isValid = false;
9494            break;
9495        }
9496        if (isValid)
9497            value = m_valueList->next();
9498    }
9499
9500    // Values are either valid or in shorthand scope.
9501    if (list->length() && (isValid || inShorthand())) {
9502        addTextDecorationProperty(propId, list.release(), important);
9503        return true;
9504    }
9505
9506    return false;
9507}
9508
9509bool CSSParser::parseTextDecorationSkip(bool important)
9510{
9511    // The text-decoration-skip property has syntax "none | [ objects || spaces || ink || edges || box-decoration ]".
9512    // However, only 'none' and 'ink' are implemented yet, so we will parse syntax "none | ink" for now.
9513    CSSParserValue* value = m_valueList->current();
9514    do {
9515        switch (value->id) {
9516        case CSSValueNone:
9517        case CSSValueAuto:
9518        case CSSValueInk:
9519        case CSSValueObjects:
9520            addProperty(CSSPropertyWebkitTextDecorationSkip, cssValuePool().createIdentifierValue(value->id), important);
9521            return true;
9522        default:
9523            break;
9524        }
9525    } while ((value = m_valueList->next()));
9526    return false;
9527}
9528
9529bool CSSParser::parseTextUnderlinePosition(bool important)
9530{
9531    // The text-underline-position property has sintax "auto | alphabetic | [ under || [ left | right ] ]".
9532    // However, values 'left' and 'right' are not implemented yet, so we will parse sintax
9533    // "auto | alphabetic | under" for now.
9534    CSSParserValue* value = m_valueList->current();
9535    switch (value->id) {
9536    case CSSValueAuto:
9537    case CSSValueAlphabetic:
9538    case CSSValueUnder:
9539        if (m_valueList->next())
9540            return false;
9541
9542        addProperty(CSSPropertyWebkitTextUnderlinePosition, cssValuePool().createIdentifierValue(value->id), important);
9543        return true;
9544    default:
9545        break;
9546    }
9547    return false;
9548}
9549
9550bool CSSParser::parseTextEmphasisStyle(bool important)
9551{
9552    unsigned valueListSize = m_valueList->size();
9553
9554    RefPtr<CSSPrimitiveValue> fill;
9555    RefPtr<CSSPrimitiveValue> shape;
9556
9557    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9558        if (value->unit == CSSPrimitiveValue::CSS_STRING) {
9559            if (fill || shape || (valueListSize != 1 && !inShorthand()))
9560                return false;
9561            addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important);
9562            m_valueList->next();
9563            return true;
9564        }
9565
9566        if (value->id == CSSValueNone) {
9567            if (fill || shape || (valueListSize != 1 && !inShorthand()))
9568                return false;
9569            addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important);
9570            m_valueList->next();
9571            return true;
9572        }
9573
9574        if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
9575            if (fill)
9576                return false;
9577            fill = cssValuePool().createIdentifierValue(value->id);
9578        } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
9579            if (shape)
9580                return false;
9581            shape = cssValuePool().createIdentifierValue(value->id);
9582        } else if (!inShorthand())
9583            return false;
9584        else
9585            break;
9586    }
9587
9588    if (fill && shape) {
9589        RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
9590        parsedValues->append(fill.release());
9591        parsedValues->append(shape.release());
9592        addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
9593        return true;
9594    }
9595    if (fill) {
9596        addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
9597        return true;
9598    }
9599    if (shape) {
9600        addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
9601        return true;
9602    }
9603
9604    return false;
9605}
9606
9607bool CSSParser::parseTextEmphasisPosition(bool important)
9608{
9609    bool foundOverOrUnder = false;
9610    CSSValueID overUnderValueID = CSSValueOver;
9611    bool foundLeftOrRight = false;
9612    CSSValueID leftRightValueID = CSSValueRight;
9613    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9614        switch (value->id) {
9615        case CSSValueOver:
9616            if (foundOverOrUnder)
9617                return false;
9618            foundOverOrUnder = true;
9619            overUnderValueID = CSSValueOver;
9620            break;
9621        case CSSValueUnder:
9622            if (foundOverOrUnder)
9623                return false;
9624            foundOverOrUnder = true;
9625            overUnderValueID = CSSValueUnder;
9626            break;
9627        case CSSValueLeft:
9628            if (foundLeftOrRight)
9629                return false;
9630            foundLeftOrRight = true;
9631            leftRightValueID = CSSValueLeft;
9632            break;
9633        case CSSValueRight:
9634            if (foundLeftOrRight)
9635                return false;
9636            foundLeftOrRight = true;
9637            leftRightValueID = CSSValueRight;
9638            break;
9639        default:
9640            return false;
9641        }
9642    }
9643    if (!foundOverOrUnder)
9644        return false;
9645    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9646    list->append(cssValuePool().createIdentifierValue(overUnderValueID));
9647    if (foundLeftOrRight)
9648        list->append(cssValuePool().createIdentifierValue(leftRightValueID));
9649    addProperty(CSSPropertyWebkitTextEmphasisPosition, list, important);
9650    return true;
9651}
9652
9653PassRefPtr<CSSValue> CSSParser::parseTextIndent()
9654{
9655    // <length> | <percentage> | inherit  when CSS3_TEXT is disabled.
9656    // [ <length> | <percentage> ] && [ -webkit-hanging || -webkit-each-line ]? | inherit  when CSS3_TEXT is enabled.
9657    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9658    bool hasLengthOrPercentage = false;
9659#if ENABLE(CSS3_TEXT)
9660    bool hasEachLine = false;
9661    bool hasHanging = false;
9662#endif
9663
9664    CSSParserValue* value = m_valueList->current();
9665    while (value) {
9666        if (!hasLengthOrPercentage && validUnit(value, FLength | FPercent)) {
9667            list->append(createPrimitiveNumericValue(value));
9668            hasLengthOrPercentage = true;
9669        }
9670#if ENABLE(CSS3_TEXT)
9671        else if (!hasEachLine && value->id == CSSValueWebkitEachLine) {
9672            list->append(cssValuePool().createIdentifierValue(CSSValueWebkitEachLine));
9673            hasEachLine = true;
9674        } else if (!hasHanging && value->id == CSSValueWebkitHanging) {
9675            list->append(cssValuePool().createIdentifierValue(CSSValueWebkitHanging));
9676            hasHanging = true;
9677        }
9678#endif
9679        else
9680            return 0;
9681
9682        value = m_valueList->next();
9683    }
9684
9685    if (!hasLengthOrPercentage)
9686        return 0;
9687
9688    return list.release();
9689}
9690
9691bool CSSParser::parseLineBoxContain(bool important)
9692{
9693    LineBoxContain lineBoxContain = LineBoxContainNone;
9694
9695    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9696        if (value->id == CSSValueBlock) {
9697            if (lineBoxContain & LineBoxContainBlock)
9698                return false;
9699            lineBoxContain |= LineBoxContainBlock;
9700        } else if (value->id == CSSValueInline) {
9701            if (lineBoxContain & LineBoxContainInline)
9702                return false;
9703            lineBoxContain |= LineBoxContainInline;
9704        } else if (value->id == CSSValueFont) {
9705            if (lineBoxContain & LineBoxContainFont)
9706                return false;
9707            lineBoxContain |= LineBoxContainFont;
9708        } else if (value->id == CSSValueGlyphs) {
9709            if (lineBoxContain & LineBoxContainGlyphs)
9710                return false;
9711            lineBoxContain |= LineBoxContainGlyphs;
9712        } else if (value->id == CSSValueReplaced) {
9713            if (lineBoxContain & LineBoxContainReplaced)
9714                return false;
9715            lineBoxContain |= LineBoxContainReplaced;
9716        } else if (value->id == CSSValueInlineBox) {
9717            if (lineBoxContain & LineBoxContainInlineBox)
9718                return false;
9719            lineBoxContain |= LineBoxContainInlineBox;
9720        } else
9721            return false;
9722    }
9723
9724    if (!lineBoxContain)
9725        return false;
9726
9727    addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
9728    return true;
9729}
9730
9731bool CSSParser::parseFontFeatureTag(CSSValueList* settings)
9732{
9733    // Feature tag name consists of 4-letter characters.
9734    static const unsigned tagNameLength = 4;
9735
9736    CSSParserValue* value = m_valueList->current();
9737    // Feature tag name comes first
9738    if (value->unit != CSSPrimitiveValue::CSS_STRING)
9739        return false;
9740    if (value->string.length() != tagNameLength)
9741        return false;
9742    for (unsigned i = 0; i < tagNameLength; ++i) {
9743        // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
9744        UChar character = value->string[i];
9745        if (character < 0x20 || character > 0x7E)
9746            return false;
9747    }
9748
9749    String tag = value->string;
9750    int tagValue = 1;
9751    // Feature tag values could follow: <integer> | on | off
9752    value = m_valueList->next();
9753    if (value) {
9754        if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
9755            tagValue = clampToInteger(value->fValue);
9756            if (tagValue < 0)
9757                return false;
9758            m_valueList->next();
9759        } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
9760            tagValue = value->id == CSSValueOn;
9761            m_valueList->next();
9762        }
9763    }
9764    settings->append(CSSFontFeatureValue::create(tag, tagValue));
9765    return true;
9766}
9767
9768bool CSSParser::parseFontFeatureSettings(bool important)
9769{
9770    if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) {
9771        RefPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal);
9772        m_valueList->next();
9773        addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
9774        return true;
9775    }
9776
9777    RefPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
9778    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9779        if (!parseFontFeatureTag(settings.get()))
9780            return false;
9781
9782        // If the list isn't parsed fully, the current value should be comma.
9783        value = m_valueList->current();
9784        if (value && !isComma(value))
9785            return false;
9786    }
9787    if (settings->length()) {
9788        addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important);
9789        return true;
9790    }
9791    return false;
9792}
9793
9794bool CSSParser::parseFontVariantLigatures(bool important)
9795{
9796    RefPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
9797    bool sawCommonLigaturesValue = false;
9798    bool sawDiscretionaryLigaturesValue = false;
9799    bool sawHistoricalLigaturesValue = false;
9800
9801    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9802        if (value->unit != CSSPrimitiveValue::CSS_IDENT)
9803            return false;
9804
9805        switch (value->id) {
9806        case CSSValueNoCommonLigatures:
9807        case CSSValueCommonLigatures:
9808            if (sawCommonLigaturesValue)
9809                return false;
9810            sawCommonLigaturesValue = true;
9811            ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9812            break;
9813        case CSSValueNoDiscretionaryLigatures:
9814        case CSSValueDiscretionaryLigatures:
9815            if (sawDiscretionaryLigaturesValue)
9816                return false;
9817            sawDiscretionaryLigaturesValue = true;
9818            ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9819            break;
9820        case CSSValueNoHistoricalLigatures:
9821        case CSSValueHistoricalLigatures:
9822            if (sawHistoricalLigaturesValue)
9823                return false;
9824            sawHistoricalLigaturesValue = true;
9825            ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9826            break;
9827        default:
9828            return false;
9829        }
9830    }
9831
9832    if (!ligatureValues->length())
9833        return false;
9834
9835    addProperty(CSSPropertyWebkitFontVariantLigatures, ligatureValues.release(), important);
9836    return true;
9837}
9838
9839bool CSSParser::parseCalculation(CSSParserValue* value, CalculationPermittedValueRange range)
9840{
9841    ASSERT(isCalculation(value));
9842
9843    CSSParserValueList* args = value->function->args.get();
9844    if (!args || !args->size())
9845        return false;
9846
9847    ASSERT(!m_parsedCalculation);
9848    m_parsedCalculation = CSSCalcValue::create(value->function->name, *args, range);
9849
9850    if (!m_parsedCalculation)
9851        return false;
9852
9853    return true;
9854}
9855
9856#define END_TOKEN 0
9857
9858#include "CSSGrammar.h"
9859
9860enum CharacterType {
9861    // Types for the main switch.
9862
9863    // The first 4 types must be grouped together, as they
9864    // represent the allowed chars in an identifier.
9865    CharacterCaselessU,
9866    CharacterIdentifierStart,
9867    CharacterNumber,
9868    CharacterDash,
9869
9870    CharacterOther,
9871    CharacterNull,
9872    CharacterWhiteSpace,
9873    CharacterEndMediaQuery,
9874    CharacterEndNthChild,
9875    CharacterQuote,
9876    CharacterExclamationMark,
9877    CharacterHashmark,
9878    CharacterDollar,
9879    CharacterAsterisk,
9880    CharacterPlus,
9881    CharacterDot,
9882    CharacterSlash,
9883    CharacterLess,
9884    CharacterAt,
9885    CharacterBackSlash,
9886    CharacterXor,
9887    CharacterVerticalBar,
9888    CharacterTilde,
9889};
9890
9891// 128 ASCII codes
9892static const CharacterType typesOfASCIICharacters[128] = {
9893/*   0 - Null               */ CharacterNull,
9894/*   1 - Start of Heading   */ CharacterOther,
9895/*   2 - Start of Text      */ CharacterOther,
9896/*   3 - End of Text        */ CharacterOther,
9897/*   4 - End of Transm.     */ CharacterOther,
9898/*   5 - Enquiry            */ CharacterOther,
9899/*   6 - Acknowledgment     */ CharacterOther,
9900/*   7 - Bell               */ CharacterOther,
9901/*   8 - Back Space         */ CharacterOther,
9902/*   9 - Horizontal Tab     */ CharacterWhiteSpace,
9903/*  10 - Line Feed          */ CharacterWhiteSpace,
9904/*  11 - Vertical Tab       */ CharacterOther,
9905/*  12 - Form Feed          */ CharacterWhiteSpace,
9906/*  13 - Carriage Return    */ CharacterWhiteSpace,
9907/*  14 - Shift Out          */ CharacterOther,
9908/*  15 - Shift In           */ CharacterOther,
9909/*  16 - Data Line Escape   */ CharacterOther,
9910/*  17 - Device Control 1   */ CharacterOther,
9911/*  18 - Device Control 2   */ CharacterOther,
9912/*  19 - Device Control 3   */ CharacterOther,
9913/*  20 - Device Control 4   */ CharacterOther,
9914/*  21 - Negative Ack.      */ CharacterOther,
9915/*  22 - Synchronous Idle   */ CharacterOther,
9916/*  23 - End of Transmit    */ CharacterOther,
9917/*  24 - Cancel             */ CharacterOther,
9918/*  25 - End of Medium      */ CharacterOther,
9919/*  26 - Substitute         */ CharacterOther,
9920/*  27 - Escape             */ CharacterOther,
9921/*  28 - File Separator     */ CharacterOther,
9922/*  29 - Group Separator    */ CharacterOther,
9923/*  30 - Record Separator   */ CharacterOther,
9924/*  31 - Unit Separator     */ CharacterOther,
9925/*  32 - Space              */ CharacterWhiteSpace,
9926/*  33 - !                  */ CharacterExclamationMark,
9927/*  34 - "                  */ CharacterQuote,
9928/*  35 - #                  */ CharacterHashmark,
9929/*  36 - $                  */ CharacterDollar,
9930/*  37 - %                  */ CharacterOther,
9931/*  38 - &                  */ CharacterOther,
9932/*  39 - '                  */ CharacterQuote,
9933/*  40 - (                  */ CharacterOther,
9934/*  41 - )                  */ CharacterEndNthChild,
9935/*  42 - *                  */ CharacterAsterisk,
9936/*  43 - +                  */ CharacterPlus,
9937/*  44 - ,                  */ CharacterOther,
9938/*  45 - -                  */ CharacterDash,
9939/*  46 - .                  */ CharacterDot,
9940/*  47 - /                  */ CharacterSlash,
9941/*  48 - 0                  */ CharacterNumber,
9942/*  49 - 1                  */ CharacterNumber,
9943/*  50 - 2                  */ CharacterNumber,
9944/*  51 - 3                  */ CharacterNumber,
9945/*  52 - 4                  */ CharacterNumber,
9946/*  53 - 5                  */ CharacterNumber,
9947/*  54 - 6                  */ CharacterNumber,
9948/*  55 - 7                  */ CharacterNumber,
9949/*  56 - 8                  */ CharacterNumber,
9950/*  57 - 9                  */ CharacterNumber,
9951/*  58 - :                  */ CharacterOther,
9952/*  59 - ;                  */ CharacterEndMediaQuery,
9953/*  60 - <                  */ CharacterLess,
9954/*  61 - =                  */ CharacterOther,
9955/*  62 - >                  */ CharacterOther,
9956/*  63 - ?                  */ CharacterOther,
9957/*  64 - @                  */ CharacterAt,
9958/*  65 - A                  */ CharacterIdentifierStart,
9959/*  66 - B                  */ CharacterIdentifierStart,
9960/*  67 - C                  */ CharacterIdentifierStart,
9961/*  68 - D                  */ CharacterIdentifierStart,
9962/*  69 - E                  */ CharacterIdentifierStart,
9963/*  70 - F                  */ CharacterIdentifierStart,
9964/*  71 - G                  */ CharacterIdentifierStart,
9965/*  72 - H                  */ CharacterIdentifierStart,
9966/*  73 - I                  */ CharacterIdentifierStart,
9967/*  74 - J                  */ CharacterIdentifierStart,
9968/*  75 - K                  */ CharacterIdentifierStart,
9969/*  76 - L                  */ CharacterIdentifierStart,
9970/*  77 - M                  */ CharacterIdentifierStart,
9971/*  78 - N                  */ CharacterIdentifierStart,
9972/*  79 - O                  */ CharacterIdentifierStart,
9973/*  80 - P                  */ CharacterIdentifierStart,
9974/*  81 - Q                  */ CharacterIdentifierStart,
9975/*  82 - R                  */ CharacterIdentifierStart,
9976/*  83 - S                  */ CharacterIdentifierStart,
9977/*  84 - T                  */ CharacterIdentifierStart,
9978/*  85 - U                  */ CharacterCaselessU,
9979/*  86 - V                  */ CharacterIdentifierStart,
9980/*  87 - W                  */ CharacterIdentifierStart,
9981/*  88 - X                  */ CharacterIdentifierStart,
9982/*  89 - Y                  */ CharacterIdentifierStart,
9983/*  90 - Z                  */ CharacterIdentifierStart,
9984/*  91 - [                  */ CharacterOther,
9985/*  92 - \                  */ CharacterBackSlash,
9986/*  93 - ]                  */ CharacterOther,
9987/*  94 - ^                  */ CharacterXor,
9988/*  95 - _                  */ CharacterIdentifierStart,
9989/*  96 - `                  */ CharacterOther,
9990/*  97 - a                  */ CharacterIdentifierStart,
9991/*  98 - b                  */ CharacterIdentifierStart,
9992/*  99 - c                  */ CharacterIdentifierStart,
9993/* 100 - d                  */ CharacterIdentifierStart,
9994/* 101 - e                  */ CharacterIdentifierStart,
9995/* 102 - f                  */ CharacterIdentifierStart,
9996/* 103 - g                  */ CharacterIdentifierStart,
9997/* 104 - h                  */ CharacterIdentifierStart,
9998/* 105 - i                  */ CharacterIdentifierStart,
9999/* 106 - j                  */ CharacterIdentifierStart,
10000/* 107 - k                  */ CharacterIdentifierStart,
10001/* 108 - l                  */ CharacterIdentifierStart,
10002/* 109 - m                  */ CharacterIdentifierStart,
10003/* 110 - n                  */ CharacterIdentifierStart,
10004/* 111 - o                  */ CharacterIdentifierStart,
10005/* 112 - p                  */ CharacterIdentifierStart,
10006/* 113 - q                  */ CharacterIdentifierStart,
10007/* 114 - r                  */ CharacterIdentifierStart,
10008/* 115 - s                  */ CharacterIdentifierStart,
10009/* 116 - t                  */ CharacterIdentifierStart,
10010/* 117 - u                  */ CharacterCaselessU,
10011/* 118 - v                  */ CharacterIdentifierStart,
10012/* 119 - w                  */ CharacterIdentifierStart,
10013/* 120 - x                  */ CharacterIdentifierStart,
10014/* 121 - y                  */ CharacterIdentifierStart,
10015/* 122 - z                  */ CharacterIdentifierStart,
10016/* 123 - {                  */ CharacterEndMediaQuery,
10017/* 124 - |                  */ CharacterVerticalBar,
10018/* 125 - }                  */ CharacterOther,
10019/* 126 - ~                  */ CharacterTilde,
10020/* 127 - Delete             */ CharacterOther,
10021};
10022
10023// Utility functions for the CSS tokenizer.
10024
10025template <typename CharacterType>
10026static inline bool isCSSLetter(CharacterType character)
10027{
10028    return character >= 128 || typesOfASCIICharacters[character] <= CharacterDash;
10029}
10030
10031template <typename CharacterType>
10032static inline bool isCSSEscape(CharacterType character)
10033{
10034    return character >= ' ' && character != 127;
10035}
10036
10037template <typename CharacterType>
10038static inline bool isURILetter(CharacterType character)
10039{
10040    return (character >= '*' && character != 127) || (character >= '#' && character <= '&') || character == '!';
10041}
10042
10043template <typename CharacterType>
10044static inline bool isIdentifierStartAfterDash(CharacterType* currentCharacter)
10045{
10046    return isASCIIAlpha(currentCharacter[0]) || currentCharacter[0] == '_' || currentCharacter[0] >= 128
10047        || (currentCharacter[0] == '\\' && isCSSEscape(currentCharacter[1]));
10048}
10049
10050template <typename CharacterType>
10051static inline bool isEqualToCSSIdentifier(CharacterType* cssString, const char* constantString)
10052{
10053    // Compare an character memory data with a zero terminated string.
10054    do {
10055        // The input must be part of an identifier if constantChar or constString
10056        // contains '-'. Otherwise toASCIILowerUnchecked('\r') would be equal to '-'.
10057        ASSERT((*constantString >= 'a' && *constantString <= 'z') || *constantString == '-');
10058        ASSERT(*constantString != '-' || isCSSLetter(*cssString));
10059        if (toASCIILowerUnchecked(*cssString++) != (*constantString++))
10060            return false;
10061    } while (*constantString);
10062    return true;
10063}
10064
10065template <typename CharacterType>
10066static inline bool isEqualToCSSCaseSensitiveIdentifier(CharacterType* string, const char* constantString)
10067{
10068    do {
10069        if (*string++ != *constantString++)
10070            return false;
10071    } while (*constantString);
10072    return true;
10073}
10074
10075template <typename CharacterType>
10076static CharacterType* checkAndSkipEscape(CharacterType* currentCharacter)
10077{
10078    // Returns with 0, if escape check is failed. Otherwise
10079    // it returns with the following character.
10080    ASSERT(*currentCharacter == '\\');
10081
10082    ++currentCharacter;
10083    if (!isCSSEscape(*currentCharacter))
10084        return 0;
10085
10086    if (isASCIIHexDigit(*currentCharacter)) {
10087        int length = 6;
10088
10089        do {
10090            ++currentCharacter;
10091        } while (isASCIIHexDigit(*currentCharacter) && --length);
10092
10093        // Optional space after the escape sequence.
10094        if (isHTMLSpace(*currentCharacter))
10095            ++currentCharacter;
10096        return currentCharacter;
10097    }
10098    return currentCharacter + 1;
10099}
10100
10101template <typename CharacterType>
10102static inline CharacterType* skipWhiteSpace(CharacterType* currentCharacter)
10103{
10104    while (isHTMLSpace(*currentCharacter))
10105        ++currentCharacter;
10106    return currentCharacter;
10107}
10108
10109// Main CSS tokenizer functions.
10110
10111template <>
10112LChar* CSSParserString::characters<LChar>() const { return characters8(); }
10113
10114template <>
10115UChar* CSSParserString::characters<UChar>() const { return characters16(); }
10116
10117template <>
10118inline LChar*& CSSParser::currentCharacter<LChar>()
10119{
10120    return m_currentCharacter8;
10121}
10122
10123template <>
10124inline UChar*& CSSParser::currentCharacter<UChar>()
10125{
10126    return m_currentCharacter16;
10127}
10128
10129UChar*& CSSParser::currentCharacter16()
10130{
10131    if (!m_currentCharacter16) {
10132        m_dataStart16 = std::make_unique<UChar[]>(m_length);
10133        m_currentCharacter16 = m_dataStart16.get();
10134    }
10135
10136    return m_currentCharacter16;
10137}
10138
10139template <>
10140inline LChar* CSSParser::tokenStart<LChar>()
10141{
10142    return m_tokenStart.ptr8;
10143}
10144
10145template <>
10146inline UChar* CSSParser::tokenStart<UChar>()
10147{
10148    return m_tokenStart.ptr16;
10149}
10150
10151CSSParser::Location CSSParser::currentLocation()
10152{
10153    Location location;
10154    location.lineNumber = m_tokenStartLineNumber;
10155    if (is8BitSource())
10156        location.token.init(tokenStart<LChar>(), currentCharacter<LChar>() - tokenStart<LChar>());
10157    else
10158        location.token.init(tokenStart<UChar>(), currentCharacter<UChar>() - tokenStart<UChar>());
10159    return location;
10160}
10161
10162template <typename CharacterType>
10163inline bool CSSParser::isIdentifierStart()
10164{
10165    // Check whether an identifier is started.
10166    return isIdentifierStartAfterDash((*currentCharacter<CharacterType>() != '-') ? currentCharacter<CharacterType>() : currentCharacter<CharacterType>() + 1);
10167}
10168
10169template <typename CharacterType>
10170static inline CharacterType* checkAndSkipString(CharacterType* currentCharacter, int quote)
10171{
10172    // Returns with 0, if string check is failed. Otherwise
10173    // it returns with the following character. This is necessary
10174    // since we cannot revert escape sequences, thus strings
10175    // must be validated before parsing.
10176    while (true) {
10177        if (UNLIKELY(*currentCharacter == quote)) {
10178            // String parsing is successful.
10179            return currentCharacter + 1;
10180        }
10181        if (UNLIKELY(!*currentCharacter)) {
10182            // String parsing is successful up to end of input.
10183            return currentCharacter;
10184        }
10185        if (UNLIKELY(*currentCharacter <= '\r' && (*currentCharacter == '\n' || (*currentCharacter | 0x1) == '\r'))) {
10186            // String parsing is failed for character '\n', '\f' or '\r'.
10187            return 0;
10188        }
10189
10190        if (LIKELY(currentCharacter[0] != '\\'))
10191            ++currentCharacter;
10192        else if (currentCharacter[1] == '\n' || currentCharacter[1] == '\f')
10193            currentCharacter += 2;
10194        else if (currentCharacter[1] == '\r')
10195            currentCharacter += currentCharacter[2] == '\n' ? 3 : 2;
10196        else {
10197            currentCharacter = checkAndSkipEscape(currentCharacter);
10198            if (!currentCharacter)
10199                return 0;
10200        }
10201    }
10202}
10203
10204template <typename CharacterType>
10205unsigned CSSParser::parseEscape(CharacterType*& src)
10206{
10207    ASSERT(*src == '\\' && isCSSEscape(src[1]));
10208
10209    unsigned unicode = 0;
10210
10211    ++src;
10212    if (isASCIIHexDigit(*src)) {
10213
10214        int length = 6;
10215
10216        do {
10217            unicode = (unicode << 4) + toASCIIHexValue(*src++);
10218        } while (--length && isASCIIHexDigit(*src));
10219
10220        // Characters above 0x10ffff are not handled.
10221        if (unicode > 0x10ffff)
10222            unicode = 0xfffd;
10223
10224        // Optional space after the escape sequence.
10225        if (isHTMLSpace(*src))
10226            ++src;
10227
10228        return unicode;
10229    }
10230
10231    return *currentCharacter<CharacterType>()++;
10232}
10233
10234template <>
10235inline void CSSParser::UnicodeToChars<LChar>(LChar*& result, unsigned unicode)
10236{
10237    ASSERT(unicode <= 0xff);
10238    *result = unicode;
10239
10240    ++result;
10241}
10242
10243template <>
10244inline void CSSParser::UnicodeToChars<UChar>(UChar*& result, unsigned unicode)
10245{
10246    // Replace unicode with a surrogate pairs when it is bigger than 0xffff
10247    if (U16_LENGTH(unicode) == 2) {
10248        *result++ = U16_LEAD(unicode);
10249        *result = U16_TRAIL(unicode);
10250    } else
10251        *result = unicode;
10252
10253    ++result;
10254}
10255
10256template <typename SrcCharacterType, typename DestCharacterType>
10257inline bool CSSParser::parseIdentifierInternal(SrcCharacterType*& src, DestCharacterType*& result, bool& hasEscape)
10258{
10259    hasEscape = false;
10260    do {
10261        if (LIKELY(*src != '\\'))
10262            *result++ = *src++;
10263        else {
10264            hasEscape = true;
10265            SrcCharacterType* savedEscapeStart = src;
10266            unsigned unicode = parseEscape<SrcCharacterType>(src);
10267            if (unicode > 0xff && sizeof(DestCharacterType) == 1) {
10268                src = savedEscapeStart;
10269                return false;
10270            }
10271            UnicodeToChars(result, unicode);
10272        }
10273    } while (isCSSLetter(src[0]) || (src[0] == '\\' && isCSSEscape(src[1])));
10274
10275    return true;
10276}
10277
10278template <typename CharacterType>
10279inline void CSSParser::parseIdentifier(CharacterType*& result, CSSParserString& resultString, bool& hasEscape)
10280{
10281    // If a valid identifier start is found, we can safely
10282    // parse the identifier until the next invalid character.
10283    ASSERT(isIdentifierStart<CharacterType>());
10284
10285    CharacterType* start = currentCharacter<CharacterType>();
10286    if (UNLIKELY(!parseIdentifierInternal(currentCharacter<CharacterType>(), result, hasEscape))) {
10287        // Found an escape we couldn't handle with 8 bits, copy what has been recognized and continue
10288        ASSERT(is8BitSource());
10289        UChar*& result16 = currentCharacter16();
10290        UChar* start16 = result16;
10291        int i = 0;
10292        for (; i < result - start; i++)
10293            result16[i] = start[i];
10294
10295        result16 += i;
10296
10297        parseIdentifierInternal(currentCharacter<CharacterType>(), result16, hasEscape);
10298
10299        resultString.init(start16, result16 - start16);
10300
10301        return;
10302    }
10303
10304    resultString.init(start, result - start);
10305}
10306
10307template <typename SrcCharacterType, typename DestCharacterType>
10308inline bool CSSParser::parseStringInternal(SrcCharacterType*& src, DestCharacterType*& result, UChar quote)
10309{
10310    while (true) {
10311        if (UNLIKELY(*src == quote)) {
10312            // String parsing is done.
10313            ++src;
10314            return true;
10315        }
10316        if (UNLIKELY(!*src)) {
10317            // String parsing is done, but don't advance pointer if at the end of input.
10318            return true;
10319        }
10320        ASSERT(*src > '\r' || (*src < '\n' && *src) || *src == '\v');
10321
10322        if (LIKELY(src[0] != '\\'))
10323            *result++ = *src++;
10324        else if (src[1] == '\n' || src[1] == '\f')
10325            src += 2;
10326        else if (src[1] == '\r')
10327            src += src[2] == '\n' ? 3 : 2;
10328        else {
10329            SrcCharacterType* savedEscapeStart = src;
10330            unsigned unicode = parseEscape<SrcCharacterType>(src);
10331            if (unicode > 0xff && sizeof(DestCharacterType) == 1) {
10332                src = savedEscapeStart;
10333                return false;
10334            }
10335            UnicodeToChars(result, unicode);
10336        }
10337    }
10338
10339    return true;
10340}
10341
10342template <typename CharacterType>
10343inline void CSSParser::parseString(CharacterType*& result, CSSParserString& resultString, UChar quote)
10344{
10345    CharacterType* start = currentCharacter<CharacterType>();
10346
10347    if (UNLIKELY(!parseStringInternal(currentCharacter<CharacterType>(), result, quote))) {
10348        // Found an escape we couldn't handle with 8 bits, copy what has been recognized and continue
10349        ASSERT(is8BitSource());
10350        UChar*& result16 = currentCharacter16();
10351        UChar* start16 = result16;
10352        int i = 0;
10353        for (; i < result - start; i++)
10354            result16[i] = start[i];
10355
10356        result16 += i;
10357
10358        parseStringInternal(currentCharacter<CharacterType>(), result16, quote);
10359
10360        resultString.init(start16, result16 - start16);
10361        return;
10362    }
10363
10364    resultString.init(start, result - start);
10365}
10366
10367template <typename CharacterType>
10368inline bool CSSParser::findURI(CharacterType*& start, CharacterType*& end, UChar& quote)
10369{
10370    start = skipWhiteSpace(currentCharacter<CharacterType>());
10371
10372    if (*start == '"' || *start == '\'') {
10373        quote = *start++;
10374        end = checkAndSkipString(start, quote);
10375        if (!end)
10376            return false;
10377    } else {
10378        quote = 0;
10379        end = start;
10380        while (isURILetter(*end)) {
10381            if (LIKELY(*end != '\\'))
10382                ++end;
10383            else {
10384                end = checkAndSkipEscape(end);
10385                if (!end)
10386                    return false;
10387            }
10388        }
10389    }
10390
10391    end = skipWhiteSpace(end);
10392    if (*end != ')')
10393        return false;
10394
10395    return true;
10396}
10397
10398template <typename SrcCharacterType, typename DestCharacterType>
10399inline bool CSSParser::parseURIInternal(SrcCharacterType*& src, DestCharacterType*& dest, UChar quote)
10400{
10401    if (quote) {
10402        ASSERT(quote == '"' || quote == '\'');
10403        return parseStringInternal(src, dest, quote);
10404    }
10405
10406    while (isURILetter(*src)) {
10407        if (LIKELY(*src != '\\'))
10408            *dest++ = *src++;
10409        else {
10410            unsigned unicode = parseEscape<SrcCharacterType>(src);
10411            if (unicode > 0xff && sizeof(SrcCharacterType) == 1)
10412                return false;
10413            UnicodeToChars(dest, unicode);
10414        }
10415    }
10416
10417    return true;
10418}
10419
10420template <typename CharacterType>
10421inline void CSSParser::parseURI(CSSParserString& string)
10422{
10423    CharacterType* uriStart;
10424    CharacterType* uriEnd;
10425    UChar quote;
10426    if (!findURI(uriStart, uriEnd, quote))
10427        return;
10428
10429    CharacterType* dest = currentCharacter<CharacterType>() = uriStart;
10430    if (LIKELY(parseURIInternal(currentCharacter<CharacterType>(), dest, quote)))
10431        string.init(uriStart, dest - uriStart);
10432    else {
10433        // An escape sequence was encountered that can't be stored in 8 bits.
10434        // Reset the current character to the start of the URI and re-parse with
10435        // a 16-bit destination.
10436        ASSERT(is8BitSource());
10437        UChar* uriStart16 = currentCharacter16();
10438        currentCharacter<CharacterType>() = uriStart;
10439        bool result = parseURIInternal(currentCharacter<CharacterType>(), currentCharacter16(), quote);
10440        ASSERT_UNUSED(result, result);
10441        string.init(uriStart16, currentCharacter16() - uriStart16);
10442    }
10443
10444    currentCharacter<CharacterType>() = uriEnd + 1;
10445    m_token = URI;
10446}
10447
10448template <typename CharacterType>
10449inline bool CSSParser::parseUnicodeRange()
10450{
10451    CharacterType* character = currentCharacter<CharacterType>() + 1;
10452    int length = 6;
10453    ASSERT(*currentCharacter<CharacterType>() == '+');
10454
10455    while (isASCIIHexDigit(*character) && length) {
10456        ++character;
10457        --length;
10458    }
10459
10460    if (length && *character == '?') {
10461        // At most 5 hex digit followed by a question mark.
10462        do {
10463            ++character;
10464            --length;
10465        } while (*character == '?' && length);
10466        currentCharacter<CharacterType>() = character;
10467        return true;
10468    }
10469
10470    if (length < 6) {
10471        // At least one hex digit.
10472        if (character[0] == '-' && isASCIIHexDigit(character[1])) {
10473            // Followed by a dash and a hex digit.
10474            ++character;
10475            length = 6;
10476            do {
10477                ++character;
10478            } while (--length && isASCIIHexDigit(*character));
10479        }
10480        currentCharacter<CharacterType>() = character;
10481        return true;
10482    }
10483    return false;
10484}
10485
10486template <typename CharacterType>
10487bool CSSParser::parseNthChild()
10488{
10489    CharacterType* character = currentCharacter<CharacterType>();
10490
10491    while (isASCIIDigit(*character))
10492        ++character;
10493    if (isASCIIAlphaCaselessEqual(*character, 'n')) {
10494        currentCharacter<CharacterType>() = character + 1;
10495        return true;
10496    }
10497    return false;
10498}
10499
10500template <typename CharacterType>
10501bool CSSParser::parseNthChildExtra()
10502{
10503    CharacterType* character = skipWhiteSpace(currentCharacter<CharacterType>());
10504    if (*character != '+' && *character != '-')
10505        return false;
10506
10507    character = skipWhiteSpace(character + 1);
10508    if (!isASCIIDigit(*character))
10509        return false;
10510
10511    do {
10512        ++character;
10513    } while (isASCIIDigit(*character));
10514
10515    currentCharacter<CharacterType>() = character;
10516    return true;
10517}
10518
10519template <typename CharacterType>
10520inline bool CSSParser::detectFunctionTypeToken(int length)
10521{
10522    ASSERT(length > 0);
10523    CharacterType* name = tokenStart<CharacterType>();
10524
10525    switch (length) {
10526    case 3:
10527        if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't')) {
10528            m_token = NOTFUNCTION;
10529            return true;
10530        }
10531        if (isASCIIAlphaCaselessEqual(name[0], 'u') && isASCIIAlphaCaselessEqual(name[1], 'r') && isASCIIAlphaCaselessEqual(name[2], 'l')) {
10532            m_token = URI;
10533            return true;
10534        }
10535#if ENABLE(VIDEO_TRACK)
10536        if (isASCIIAlphaCaselessEqual(name[0], 'c') && isASCIIAlphaCaselessEqual(name[1], 'u') && isASCIIAlphaCaselessEqual(name[2], 'e')) {
10537            m_token = CUEFUNCTION;
10538            return true;
10539        }
10540#endif
10541        return false;
10542
10543    case 4:
10544        if (isEqualToCSSIdentifier(name, "calc")) {
10545            m_token = CALCFUNCTION;
10546            return true;
10547        }
10548        return false;
10549
10550    case 9:
10551        if (isEqualToCSSIdentifier(name, "nth-child")) {
10552            m_parsingMode = NthChildMode;
10553            return true;
10554        }
10555        return false;
10556
10557    case 11:
10558        if (isEqualToCSSIdentifier(name, "nth-of-type")) {
10559            m_parsingMode = NthChildMode;
10560            return true;
10561        }
10562        return false;
10563
10564    case 14:
10565        if (isEqualToCSSIdentifier(name, "nth-last-child")) {
10566            m_parsingMode = NthChildMode;
10567            return true;
10568        }
10569        return false;
10570
10571    case 16:
10572        if (isEqualToCSSIdentifier(name, "nth-last-of-type")) {
10573            m_parsingMode = NthChildMode;
10574            return true;
10575        }
10576        return false;
10577    }
10578
10579    return false;
10580}
10581
10582template <typename CharacterType>
10583inline void CSSParser::detectMediaQueryToken(int length)
10584{
10585    ASSERT(m_parsingMode == MediaQueryMode);
10586    CharacterType* name = tokenStart<CharacterType>();
10587
10588    if (length == 3) {
10589        if (isASCIIAlphaCaselessEqual(name[0], 'a') && isASCIIAlphaCaselessEqual(name[1], 'n') && isASCIIAlphaCaselessEqual(name[2], 'd'))
10590            m_token = MEDIA_AND;
10591        else if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't'))
10592            m_token = MEDIA_NOT;
10593    } else if (length == 4) {
10594        if (isASCIIAlphaCaselessEqual(name[0], 'o') && isASCIIAlphaCaselessEqual(name[1], 'n')
10595                && isASCIIAlphaCaselessEqual(name[2], 'l') && isASCIIAlphaCaselessEqual(name[3], 'y'))
10596            m_token = MEDIA_ONLY;
10597    }
10598}
10599
10600template <typename CharacterType>
10601inline void CSSParser::detectNumberToken(CharacterType* type, int length)
10602{
10603    ASSERT(length > 0);
10604
10605    switch (toASCIILowerUnchecked(type[0])) {
10606    case 'c':
10607        if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'm'))
10608            m_token = CMS;
10609        else if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'h'))
10610            m_token = CHS;
10611        return;
10612
10613    case 'd':
10614        if (length == 3 && isASCIIAlphaCaselessEqual(type[1], 'e') && isASCIIAlphaCaselessEqual(type[2], 'g'))
10615            m_token = DEGS;
10616#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
10617        else if (length > 2 && isASCIIAlphaCaselessEqual(type[1], 'p')) {
10618            if (length == 4) {
10619                // There is a discussion about the name of this unit on www-style.
10620                // Keep this compile time guard in place until that is resolved.
10621                // http://lists.w3.org/Archives/Public/www-style/2012May/0915.html
10622                if (isASCIIAlphaCaselessEqual(type[2], 'p') && isASCIIAlphaCaselessEqual(type[3], 'x'))
10623                    m_token = DPPX;
10624                else if (isASCIIAlphaCaselessEqual(type[2], 'c') && isASCIIAlphaCaselessEqual(type[3], 'm'))
10625                    m_token = DPCM;
10626            } else if (length == 3 && isASCIIAlphaCaselessEqual(type[2], 'i'))
10627                    m_token = DPI;
10628        }
10629#endif
10630        return;
10631
10632    case 'e':
10633        if (length == 2) {
10634            if (isASCIIAlphaCaselessEqual(type[1], 'm'))
10635                m_token = EMS;
10636            else if (isASCIIAlphaCaselessEqual(type[1], 'x'))
10637                m_token = EXS;
10638        }
10639        return;
10640
10641    case 'f':
10642        if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'r'))
10643            m_token = FR;
10644        return;
10645    case 'g':
10646        if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'r')
10647                && isASCIIAlphaCaselessEqual(type[2], 'a') && isASCIIAlphaCaselessEqual(type[3], 'd'))
10648            m_token = GRADS;
10649        return;
10650
10651    case 'h':
10652        if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'z'))
10653            m_token = HERTZ;
10654        return;
10655
10656    case 'i':
10657        if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'n'))
10658            m_token = INS;
10659        return;
10660
10661    case 'k':
10662        if (length == 3 && isASCIIAlphaCaselessEqual(type[1], 'h') && isASCIIAlphaCaselessEqual(type[2], 'z'))
10663            m_token = KHERTZ;
10664        return;
10665
10666    case 'm':
10667        if (length == 2) {
10668            if (isASCIIAlphaCaselessEqual(type[1], 'm'))
10669                m_token = MMS;
10670            else if (isASCIIAlphaCaselessEqual(type[1], 's'))
10671                m_token = MSECS;
10672        }
10673        return;
10674
10675    case 'p':
10676        if (length == 2) {
10677            if (isASCIIAlphaCaselessEqual(type[1], 'x'))
10678                m_token = PXS;
10679            else if (isASCIIAlphaCaselessEqual(type[1], 't'))
10680                m_token = PTS;
10681            else if (isASCIIAlphaCaselessEqual(type[1], 'c'))
10682                m_token = PCS;
10683        }
10684        return;
10685
10686    case 'r':
10687        if (length == 3) {
10688            if (isASCIIAlphaCaselessEqual(type[1], 'a') && isASCIIAlphaCaselessEqual(type[2], 'd'))
10689                m_token = RADS;
10690            else if (isASCIIAlphaCaselessEqual(type[1], 'e') && isASCIIAlphaCaselessEqual(type[2], 'm'))
10691                m_token = REMS;
10692        }
10693        return;
10694
10695    case 's':
10696        if (length == 1)
10697            m_token = SECS;
10698        return;
10699
10700    case 't':
10701        if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'u')
10702                && isASCIIAlphaCaselessEqual(type[2], 'r') && isASCIIAlphaCaselessEqual(type[3], 'n'))
10703            m_token = TURNS;
10704        return;
10705    case 'v':
10706        if (length == 2) {
10707            if (isASCIIAlphaCaselessEqual(type[1], 'w'))
10708                m_token = VW;
10709            else if (isASCIIAlphaCaselessEqual(type[1], 'h'))
10710                m_token = VH;
10711        } else if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'm')) {
10712            if (isASCIIAlphaCaselessEqual(type[2], 'i') && isASCIIAlphaCaselessEqual(type[3], 'n'))
10713                m_token = VMIN;
10714            else if (isASCIIAlphaCaselessEqual(type[2], 'a') && isASCIIAlphaCaselessEqual(type[3], 'x'))
10715                m_token = VMAX;
10716        }
10717        return;
10718
10719    default:
10720        if (type[0] == '_' && length == 5 && type[1] == '_' && isASCIIAlphaCaselessEqual(type[2], 'q')
10721                && isASCIIAlphaCaselessEqual(type[3], 'e') && isASCIIAlphaCaselessEqual(type[4], 'm'))
10722            m_token = QEMS;
10723        return;
10724    }
10725}
10726
10727template <typename CharacterType>
10728inline void CSSParser::detectDashToken(int length)
10729{
10730    CharacterType* name = tokenStart<CharacterType>();
10731
10732    if (length == 11) {
10733        if (isASCIIAlphaCaselessEqual(name[10], 'y') && isEqualToCSSIdentifier(name + 1, "webkit-an"))
10734            m_token = ANYFUNCTION;
10735        else if (isASCIIAlphaCaselessEqual(name[10], 'n') && isEqualToCSSIdentifier(name + 1, "webkit-mi"))
10736            m_token = MINFUNCTION;
10737        else if (isASCIIAlphaCaselessEqual(name[10], 'x') && isEqualToCSSIdentifier(name + 1, "webkit-ma"))
10738            m_token = MAXFUNCTION;
10739    } else if (length == 12 && isEqualToCSSIdentifier(name + 1, "webkit-calc"))
10740        m_token = CALCFUNCTION;
10741}
10742
10743template <typename CharacterType>
10744inline void CSSParser::detectAtToken(int length, bool hasEscape)
10745{
10746    CharacterType* name = tokenStart<CharacterType>();
10747    ASSERT(name[0] == '@' && length >= 2);
10748
10749    // charset, font-face, import, media, namespace, page, supports,
10750    // -webkit-keyframes, and -webkit-mediaquery are not affected by hasEscape.
10751    switch (toASCIILowerUnchecked(name[1])) {
10752    case 'b':
10753        if (hasEscape)
10754            return;
10755
10756        switch (length) {
10757        case 12:
10758            if (isEqualToCSSIdentifier(name + 2, "ottom-left"))
10759                m_token = BOTTOMLEFT_SYM;
10760            return;
10761
10762        case 13:
10763            if (isEqualToCSSIdentifier(name + 2, "ottom-right"))
10764                m_token = BOTTOMRIGHT_SYM;
10765            return;
10766
10767        case 14:
10768            if (isEqualToCSSIdentifier(name + 2, "ottom-center"))
10769                m_token = BOTTOMCENTER_SYM;
10770            return;
10771
10772        case 19:
10773            if (isEqualToCSSIdentifier(name + 2, "ottom-left-corner"))
10774                m_token = BOTTOMLEFTCORNER_SYM;
10775            return;
10776
10777        case 20:
10778            if (isEqualToCSSIdentifier(name + 2, "ottom-right-corner"))
10779                m_token = BOTTOMRIGHTCORNER_SYM;
10780            return;
10781        }
10782        return;
10783
10784    case 'c':
10785        if (length == 8 && isEqualToCSSIdentifier(name + 2, "harset"))
10786            m_token = CHARSET_SYM;
10787        return;
10788
10789    case 'f':
10790        if (length == 10 && isEqualToCSSIdentifier(name + 2, "ont-face"))
10791            m_token = FONT_FACE_SYM;
10792        return;
10793
10794    case 'i':
10795        if (length == 7 && isEqualToCSSIdentifier(name + 2, "mport")) {
10796            m_parsingMode = MediaQueryMode;
10797            m_token = IMPORT_SYM;
10798        }
10799        return;
10800
10801    case 'l':
10802        if (hasEscape)
10803            return;
10804
10805        if (length == 9) {
10806            if (isEqualToCSSIdentifier(name + 2, "eft-top"))
10807                m_token = LEFTTOP_SYM;
10808        } else if (length == 12) {
10809            // Checking the last character first could further reduce the possibile cases.
10810            if (isASCIIAlphaCaselessEqual(name[11], 'e') && isEqualToCSSIdentifier(name + 2, "eft-middl"))
10811                m_token = LEFTMIDDLE_SYM;
10812            else if (isASCIIAlphaCaselessEqual(name[11], 'm') && isEqualToCSSIdentifier(name + 2, "eft-botto"))
10813                m_token = LEFTBOTTOM_SYM;
10814        }
10815        return;
10816
10817    case 'm':
10818        if (length == 6 && isEqualToCSSIdentifier(name + 2, "edia")) {
10819            m_parsingMode = MediaQueryMode;
10820            m_token = MEDIA_SYM;
10821        }
10822        return;
10823
10824    case 'n':
10825        if (length == 10 && isEqualToCSSIdentifier(name + 2, "amespace"))
10826            m_token = NAMESPACE_SYM;
10827        return;
10828
10829    case 'p':
10830        if (length == 5 && isEqualToCSSIdentifier(name + 2, "age"))
10831            m_token = PAGE_SYM;
10832        return;
10833
10834    case 'r':
10835        if (hasEscape)
10836            return;
10837
10838        if (length == 10) {
10839            if (isEqualToCSSIdentifier(name + 2, "ight-top"))
10840                m_token = RIGHTTOP_SYM;
10841        } else if (length == 13) {
10842            // Checking the last character first could further reduce the possibile cases.
10843            if (isASCIIAlphaCaselessEqual(name[12], 'e') && isEqualToCSSIdentifier(name + 2, "ight-middl"))
10844                m_token = RIGHTMIDDLE_SYM;
10845            else if (isASCIIAlphaCaselessEqual(name[12], 'm') && isEqualToCSSIdentifier(name + 2, "ight-botto"))
10846                m_token = RIGHTBOTTOM_SYM;
10847        }
10848        return;
10849
10850#if ENABLE(CSS3_CONDITIONAL_RULES)
10851    case 's':
10852        if (length == 9 && isEqualToCSSIdentifier(name + 2, "upports")) {
10853            m_parsingMode = SupportsMode;
10854            m_token = SUPPORTS_SYM;
10855        }
10856        return;
10857#endif
10858
10859    case 't':
10860        if (hasEscape)
10861            return;
10862
10863        switch (length) {
10864        case 9:
10865            if (isEqualToCSSIdentifier(name + 2, "op-left"))
10866                m_token = TOPLEFT_SYM;
10867            return;
10868
10869        case 10:
10870            if (isEqualToCSSIdentifier(name + 2, "op-right"))
10871                m_token = TOPRIGHT_SYM;
10872            return;
10873
10874        case 11:
10875            if (isEqualToCSSIdentifier(name + 2, "op-center"))
10876                m_token = TOPCENTER_SYM;
10877            return;
10878
10879        case 16:
10880            if (isEqualToCSSIdentifier(name + 2, "op-left-corner"))
10881                m_token = TOPLEFTCORNER_SYM;
10882            return;
10883
10884        case 17:
10885            if (isEqualToCSSIdentifier(name + 2, "op-right-corner"))
10886                m_token = TOPRIGHTCORNER_SYM;
10887            return;
10888        }
10889        return;
10890
10891    case '-':
10892        switch (length) {
10893        case 13:
10894            if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-rule"))
10895                m_token = WEBKIT_RULE_SYM;
10896            return;
10897
10898        case 14:
10899            if (hasEscape)
10900                return;
10901
10902            // Checking the last character first could further reduce the possibile cases.
10903            if (isASCIIAlphaCaselessEqual(name[13], 's') && isEqualToCSSIdentifier(name + 2, "webkit-decl"))
10904                m_token = WEBKIT_DECLS_SYM;
10905            else if (isASCIIAlphaCaselessEqual(name[13], 'e') && isEqualToCSSIdentifier(name + 2, "webkit-valu"))
10906                m_token = WEBKIT_VALUE_SYM;
10907            return;
10908
10909        case 15:
10910            if (hasEscape)
10911                return;
10912
10913#if ENABLE(CSS_REGIONS)
10914            if (isASCIIAlphaCaselessEqual(name[14], 'n') && isEqualToCSSIdentifier(name + 2, "webkit-regio"))
10915                m_token = WEBKIT_REGION_RULE_SYM;
10916#endif
10917            return;
10918
10919        case 17:
10920            if (hasEscape)
10921                return;
10922
10923            if (isASCIIAlphaCaselessEqual(name[16], 'r') && isEqualToCSSIdentifier(name + 2, "webkit-selecto"))
10924                m_token = WEBKIT_SELECTOR_SYM;
10925#if ENABLE(CSS_DEVICE_ADAPTATION)
10926            else if (isASCIIAlphaCaselessEqual(name[16], 't') && isEqualToCSSIdentifier(name + 2, "webkit-viewpor"))
10927                m_token = WEBKIT_VIEWPORT_RULE_SYM;
10928#endif
10929            return;
10930
10931        case 18:
10932            if (isEqualToCSSIdentifier(name + 2, "webkit-keyframes"))
10933                m_token = WEBKIT_KEYFRAMES_SYM;
10934#if ENABLE(PICTURE_SIZES)
10935            else if (isEqualToCSSIdentifier(name + 2, "webkit-sizesattr"))
10936                m_token = WEBKIT_SIZESATTR_SYM;
10937#endif
10938            return;
10939
10940        case 19:
10941            if (isEqualToCSSIdentifier(name + 2, "webkit-mediaquery")) {
10942                m_parsingMode = MediaQueryMode;
10943                m_token = WEBKIT_MEDIAQUERY_SYM;
10944            }
10945            return;
10946
10947        case 22:
10948            if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-keyframe-rule"))
10949                m_token = WEBKIT_KEYFRAME_RULE_SYM;
10950            return;
10951
10952        case 27:
10953#if ENABLE(CSS3_CONDITIONAL_RULES)
10954            if (isEqualToCSSIdentifier(name + 2, "webkit-supports-condition")) {
10955                m_parsingMode = SupportsMode;
10956                m_token = WEBKIT_SUPPORTS_CONDITION_SYM;
10957            }
10958#endif
10959            return;
10960        }
10961    }
10962}
10963
10964#if ENABLE(CSS3_CONDITIONAL_RULES)
10965template <typename CharacterType>
10966inline void CSSParser::detectSupportsToken(int length)
10967{
10968    ASSERT(m_parsingMode == SupportsMode);
10969    CharacterType* name = tokenStart<CharacterType>();
10970
10971    if (length == 2) {
10972        if (isASCIIAlphaCaselessEqual(name[0], 'o') && isASCIIAlphaCaselessEqual(name[1], 'r'))
10973            m_token = SUPPORTS_OR;
10974    } else if (length == 3) {
10975        if (isASCIIAlphaCaselessEqual(name[0], 'a') && isASCIIAlphaCaselessEqual(name[1], 'n') && isASCIIAlphaCaselessEqual(name[2], 'd'))
10976            m_token = SUPPORTS_AND;
10977        else if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't'))
10978            m_token = SUPPORTS_NOT;
10979    }
10980}
10981#endif
10982
10983template <typename SrcCharacterType>
10984int CSSParser::realLex(void* yylvalWithoutType)
10985{
10986    YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType);
10987    // Write pointer for the next character.
10988    SrcCharacterType* result;
10989    CSSParserString resultString;
10990    bool hasEscape;
10991
10992    // The input buffer is terminated by a \0 character, so
10993    // it is safe to read one character ahead of a known non-null.
10994#ifndef NDEBUG
10995    // In debug we check with an ASSERT that the length is > 0 for string types.
10996    yylval->string.clear();
10997#endif
10998
10999restartAfterComment:
11000    result = currentCharacter<SrcCharacterType>();
11001    setTokenStart(result);
11002    m_tokenStartLineNumber = m_lineNumber;
11003    m_token = *currentCharacter<SrcCharacterType>();
11004    ++currentCharacter<SrcCharacterType>();
11005
11006    switch ((m_token <= 127) ? typesOfASCIICharacters[m_token] : CharacterIdentifierStart) {
11007    case CharacterCaselessU:
11008        if (UNLIKELY(*currentCharacter<SrcCharacterType>() == '+')) {
11009            if (parseUnicodeRange<SrcCharacterType>()) {
11010                m_token = UNICODERANGE;
11011                yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
11012                break;
11013            }
11014        }
11015        FALLTHROUGH; // To CharacterIdentifierStart.
11016
11017    case CharacterIdentifierStart:
11018        --currentCharacter<SrcCharacterType>();
11019        parseIdentifier(result, yylval->string, hasEscape);
11020        m_token = IDENT;
11021
11022        if (UNLIKELY(*currentCharacter<SrcCharacterType>() == '(')) {
11023#if ENABLE(CSS3_CONDITIONAL_RULES)
11024            if (m_parsingMode == SupportsMode && !hasEscape) {
11025                detectSupportsToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
11026                if (m_token != IDENT)
11027                    break;
11028            }
11029#endif
11030            m_token = FUNCTION;
11031            bool shouldSkipParenthesis = true;
11032            if (!hasEscape) {
11033                bool detected = detectFunctionTypeToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
11034                if (!detected && m_parsingMode == MediaQueryMode) {
11035                    // ... and(max-width: 480px) ... looks like a function, but in fact it is not,
11036                    // so run more detection code in the MediaQueryMode.
11037                    detectMediaQueryToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
11038                    shouldSkipParenthesis = false;
11039                }
11040            }
11041
11042            if (LIKELY(shouldSkipParenthesis)) {
11043                ++currentCharacter<SrcCharacterType>();
11044                ++result;
11045                ++yylval->string.m_length;
11046            }
11047
11048            if (token() == URI) {
11049                m_token = FUNCTION;
11050                // Check whether it is really an URI.
11051                if (yylval->string.is8Bit())
11052                    parseURI<LChar>(yylval->string);
11053                else
11054                    parseURI<UChar>(yylval->string);
11055            }
11056        } else if (UNLIKELY(m_parsingMode != NormalMode) && !hasEscape) {
11057            if (m_parsingMode == MediaQueryMode)
11058                detectMediaQueryToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
11059#if ENABLE(CSS3_CONDITIONAL_RULES)
11060            else if (m_parsingMode == SupportsMode)
11061                detectSupportsToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
11062#endif
11063            else if (m_parsingMode == NthChildMode && isASCIIAlphaCaselessEqual(tokenStart<SrcCharacterType>()[0], 'n')) {
11064                if (result - tokenStart<SrcCharacterType>() == 1) {
11065                    // String "n" is IDENT but "n+1" is NTH.
11066                    if (parseNthChildExtra<SrcCharacterType>()) {
11067                        m_token = NTH;
11068                        yylval->string.m_length = currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>();
11069                    }
11070                } else if (result - tokenStart<SrcCharacterType>() >= 2 && tokenStart<SrcCharacterType>()[1] == '-') {
11071                    // String "n-" is IDENT but "n-1" is NTH.
11072                    // Set currentCharacter to '-' to continue parsing.
11073                    SrcCharacterType* nextCharacter = result;
11074                    currentCharacter<SrcCharacterType>() = tokenStart<SrcCharacterType>() + 1;
11075                    if (parseNthChildExtra<SrcCharacterType>()) {
11076                        m_token = NTH;
11077                        yylval->string.setLength(currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
11078                    } else {
11079                        // Revert the change to currentCharacter if unsuccessful.
11080                        currentCharacter<SrcCharacterType>() = nextCharacter;
11081                    }
11082                }
11083            }
11084        }
11085        break;
11086
11087    case CharacterDot:
11088        if (!isASCIIDigit(currentCharacter<SrcCharacterType>()[0]))
11089            break;
11090        FALLTHROUGH; // To CharacterNumber.
11091
11092    case CharacterNumber: {
11093        bool dotSeen = (m_token == '.');
11094
11095        while (true) {
11096            if (!isASCIIDigit(currentCharacter<SrcCharacterType>()[0])) {
11097                // Only one dot is allowed for a number,
11098                // and it must be followed by a digit.
11099                if (currentCharacter<SrcCharacterType>()[0] != '.' || dotSeen || !isASCIIDigit(currentCharacter<SrcCharacterType>()[1]))
11100                    break;
11101                dotSeen = true;
11102            }
11103            ++currentCharacter<SrcCharacterType>();
11104        }
11105
11106        if (UNLIKELY(m_parsingMode == NthChildMode) && !dotSeen && isASCIIAlphaCaselessEqual(*currentCharacter<SrcCharacterType>(), 'n')) {
11107            // "[0-9]+n" is always an NthChild.
11108            ++currentCharacter<SrcCharacterType>();
11109            parseNthChildExtra<SrcCharacterType>();
11110            m_token = NTH;
11111            yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
11112            break;
11113        }
11114
11115        // Use SVG parser for numbers on SVG presentation attributes.
11116        if (m_context.mode == SVGAttributeMode) {
11117            // We need to take care of units like 'em' or 'ex'.
11118            SrcCharacterType* character = currentCharacter<SrcCharacterType>();
11119            if (isASCIIAlphaCaselessEqual(*character, 'e')) {
11120                ASSERT(character - tokenStart<SrcCharacterType>() > 0);
11121                ++character;
11122                if (*character == '-' || *character == '+' || isASCIIDigit(*character)) {
11123                    ++character;
11124                    while (isASCIIDigit(*character))
11125                        ++character;
11126                    // Use FLOATTOKEN if the string contains exponents.
11127                    dotSeen = true;
11128                    currentCharacter<SrcCharacterType>() = character;
11129                }
11130            }
11131            if (!parseSVGNumber(tokenStart<SrcCharacterType>(), character - tokenStart<SrcCharacterType>(), yylval->number))
11132                break;
11133        } else
11134            yylval->number = charactersToDouble(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
11135
11136        // Type of the function.
11137        if (isIdentifierStart<SrcCharacterType>()) {
11138            SrcCharacterType* type = currentCharacter<SrcCharacterType>();
11139            result = currentCharacter<SrcCharacterType>();
11140
11141            parseIdentifier(result, resultString, hasEscape);
11142
11143            m_token = DIMEN;
11144            if (!hasEscape)
11145                detectNumberToken(type, currentCharacter<SrcCharacterType>() - type);
11146
11147            if (m_token == DIMEN) {
11148                // The decoded number is overwritten, but this is intentional.
11149                yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
11150            }
11151        } else if (*currentCharacter<SrcCharacterType>() == '%') {
11152            // Although the CSS grammar says {num}% we follow
11153            // webkit at the moment which uses {num}%+.
11154            do {
11155                ++currentCharacter<SrcCharacterType>();
11156            } while (*currentCharacter<SrcCharacterType>() == '%');
11157            m_token = PERCENTAGE;
11158        } else
11159            m_token = dotSeen ? FLOATTOKEN : INTEGER;
11160        break;
11161    }
11162
11163    case CharacterDash:
11164        if (isIdentifierStartAfterDash(currentCharacter<SrcCharacterType>())) {
11165            --currentCharacter<SrcCharacterType>();
11166            parseIdentifier(result, resultString, hasEscape);
11167            m_token = IDENT;
11168
11169            if (*currentCharacter<SrcCharacterType>() == '(') {
11170                m_token = FUNCTION;
11171                if (!hasEscape)
11172                    detectDashToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
11173                ++currentCharacter<SrcCharacterType>();
11174                ++result;
11175            } else if (UNLIKELY(m_parsingMode == NthChildMode) && !hasEscape && isASCIIAlphaCaselessEqual(tokenStart<SrcCharacterType>()[1], 'n')) {
11176                if (result - tokenStart<SrcCharacterType>() == 2) {
11177                    // String "-n" is IDENT but "-n+1" is NTH.
11178                    if (parseNthChildExtra<SrcCharacterType>()) {
11179                        m_token = NTH;
11180                        result = currentCharacter<SrcCharacterType>();
11181                    }
11182                } else if (result - tokenStart<SrcCharacterType>() >= 3 && tokenStart<SrcCharacterType>()[2] == '-') {
11183                    // String "-n-" is IDENT but "-n-1" is NTH.
11184                    // Set currentCharacter to second '-' of '-n-' to continue parsing.
11185                    SrcCharacterType* nextCharacter = result;
11186                    currentCharacter<SrcCharacterType>() = tokenStart<SrcCharacterType>() + 2;
11187                    if (parseNthChildExtra<SrcCharacterType>()) {
11188                        m_token = NTH;
11189                        result = currentCharacter<SrcCharacterType>();
11190                    } else {
11191                        // Revert the change to currentCharacter if unsuccessful.
11192                        currentCharacter<SrcCharacterType>() = nextCharacter;
11193                    }
11194                }
11195            }
11196            resultString.setLength(result - tokenStart<SrcCharacterType>());
11197            yylval->string = resultString;
11198        } else if (currentCharacter<SrcCharacterType>()[0] == '-' && currentCharacter<SrcCharacterType>()[1] == '>') {
11199            currentCharacter<SrcCharacterType>() += 2;
11200            m_token = SGML_CD;
11201        } else if (UNLIKELY(m_parsingMode == NthChildMode)) {
11202            // "-[0-9]+n" is always an NthChild.
11203            if (parseNthChild<SrcCharacterType>()) {
11204                parseNthChildExtra<SrcCharacterType>();
11205                m_token = NTH;
11206                yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
11207            }
11208        }
11209        break;
11210
11211    case CharacterOther:
11212        // m_token is simply the current character.
11213        break;
11214
11215    case CharacterNull:
11216        // Do not advance pointer at the end of input.
11217        --currentCharacter<SrcCharacterType>();
11218        break;
11219
11220    case CharacterWhiteSpace:
11221        m_token = WHITESPACE;
11222        // Might start with a '\n'.
11223        --currentCharacter<SrcCharacterType>();
11224        do {
11225            if (*currentCharacter<SrcCharacterType>() == '\n')
11226                ++m_lineNumber;
11227            ++currentCharacter<SrcCharacterType>();
11228        } while (*currentCharacter<SrcCharacterType>() <= ' ' && (typesOfASCIICharacters[*currentCharacter<SrcCharacterType>()] == CharacterWhiteSpace));
11229        break;
11230
11231    case CharacterEndMediaQuery:
11232        if (m_parsingMode == MediaQueryMode)
11233            m_parsingMode = NormalMode;
11234        break;
11235
11236    case CharacterEndNthChild:
11237        if (m_parsingMode == NthChildMode)
11238            m_parsingMode = NormalMode;
11239        break;
11240
11241    case CharacterQuote:
11242        if (checkAndSkipString(currentCharacter<SrcCharacterType>(), m_token)) {
11243            ++result;
11244            parseString<SrcCharacterType>(result, yylval->string, m_token);
11245            m_token = STRING;
11246        }
11247        break;
11248
11249    case CharacterExclamationMark: {
11250        SrcCharacterType* start = skipWhiteSpace(currentCharacter<SrcCharacterType>());
11251        if (isEqualToCSSIdentifier(start, "important")) {
11252            m_token = IMPORTANT_SYM;
11253            currentCharacter<SrcCharacterType>() = start + 9;
11254        }
11255        break;
11256    }
11257
11258    case CharacterHashmark: {
11259        SrcCharacterType* start = currentCharacter<SrcCharacterType>();
11260        result = currentCharacter<SrcCharacterType>();
11261
11262        if (isASCIIDigit(*currentCharacter<SrcCharacterType>())) {
11263            // This must be a valid hex number token.
11264            do {
11265                ++currentCharacter<SrcCharacterType>();
11266            } while (isASCIIHexDigit(*currentCharacter<SrcCharacterType>()));
11267            m_token = HEX;
11268            yylval->string.init(start, currentCharacter<SrcCharacterType>() - start);
11269        } else if (isIdentifierStart<SrcCharacterType>()) {
11270            m_token = IDSEL;
11271            parseIdentifier(result, yylval->string, hasEscape);
11272            if (!hasEscape) {
11273                // Check whether the identifier is also a valid hex number.
11274                SrcCharacterType* current = start;
11275                m_token = HEX;
11276                do {
11277                    if (!isASCIIHexDigit(*current)) {
11278                        m_token = IDSEL;
11279                        break;
11280                    }
11281                    ++current;
11282                } while (current < result);
11283            }
11284        }
11285        break;
11286    }
11287
11288    case CharacterSlash:
11289        // Ignore comments. They are not even considered as white spaces.
11290        if (*currentCharacter<SrcCharacterType>() == '*') {
11291            ++currentCharacter<SrcCharacterType>();
11292            while (currentCharacter<SrcCharacterType>()[0] != '*' || currentCharacter<SrcCharacterType>()[1] != '/') {
11293                if (*currentCharacter<SrcCharacterType>() == '\n')
11294                    ++m_lineNumber;
11295                if (*currentCharacter<SrcCharacterType>() == '\0') {
11296                    // Unterminated comments are simply ignored.
11297                    currentCharacter<SrcCharacterType>() -= 2;
11298                    break;
11299                }
11300                ++currentCharacter<SrcCharacterType>();
11301            }
11302            currentCharacter<SrcCharacterType>() += 2;
11303            goto restartAfterComment;
11304        }
11305        break;
11306
11307    case CharacterDollar:
11308        if (*currentCharacter<SrcCharacterType>() == '=') {
11309            ++currentCharacter<SrcCharacterType>();
11310            m_token = ENDSWITH;
11311        }
11312        break;
11313
11314    case CharacterAsterisk:
11315        if (*currentCharacter<SrcCharacterType>() == '=') {
11316            ++currentCharacter<SrcCharacterType>();
11317            m_token = CONTAINS;
11318        }
11319        break;
11320
11321    case CharacterPlus:
11322        if (UNLIKELY(m_parsingMode == NthChildMode)) {
11323            // Simplest case. "+[0-9]*n" is always NthChild.
11324            if (parseNthChild<SrcCharacterType>()) {
11325                parseNthChildExtra<SrcCharacterType>();
11326                m_token = NTH;
11327                yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
11328            }
11329        }
11330        break;
11331
11332    case CharacterLess:
11333        if (currentCharacter<SrcCharacterType>()[0] == '!' && currentCharacter<SrcCharacterType>()[1] == '-' && currentCharacter<SrcCharacterType>()[2] == '-') {
11334            currentCharacter<SrcCharacterType>() += 3;
11335            m_token = SGML_CD;
11336        }
11337        break;
11338
11339    case CharacterAt:
11340        if (isIdentifierStart<SrcCharacterType>()) {
11341            m_token = ATKEYWORD;
11342            ++result;
11343            parseIdentifier(result, resultString, hasEscape);
11344            detectAtToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>(), hasEscape);
11345        }
11346        break;
11347
11348    case CharacterBackSlash:
11349        if (isCSSEscape(*currentCharacter<SrcCharacterType>())) {
11350            --currentCharacter<SrcCharacterType>();
11351            parseIdentifier(result, yylval->string, hasEscape);
11352            m_token = IDENT;
11353        }
11354        break;
11355
11356    case CharacterXor:
11357        if (*currentCharacter<SrcCharacterType>() == '=') {
11358            ++currentCharacter<SrcCharacterType>();
11359            m_token = BEGINSWITH;
11360        }
11361        break;
11362
11363    case CharacterVerticalBar:
11364        if (*currentCharacter<SrcCharacterType>() == '=') {
11365            ++currentCharacter<SrcCharacterType>();
11366            m_token = DASHMATCH;
11367        }
11368        break;
11369
11370    case CharacterTilde:
11371        if (*currentCharacter<SrcCharacterType>() == '=') {
11372            ++currentCharacter<SrcCharacterType>();
11373            m_token = INCLUDES;
11374        }
11375        break;
11376
11377    default:
11378        ASSERT_NOT_REACHED();
11379        break;
11380    }
11381
11382    return token();
11383}
11384
11385PassRefPtr<StyleRuleBase> CSSParser::createImportRule(const CSSParserString& url, PassRefPtr<MediaQuerySet> media)
11386{
11387    if (!media || !m_allowImportRules) {
11388        popRuleData();
11389        return 0;
11390    }
11391    RefPtr<StyleRuleImport> rule = StyleRuleImport::create(url, media);
11392    processAndAddNewRuleToSourceTreeIfNeeded();
11393    return rule.release();
11394}
11395
11396PassRefPtr<StyleRuleBase> CSSParser::createMediaRule(PassRefPtr<MediaQuerySet> media, RuleList* rules)
11397{
11398    m_allowImportRules = m_allowNamespaceDeclarations = false;
11399    RefPtr<StyleRuleMedia> rule;
11400    RuleList emptyRules;
11401    if (!media) {
11402        // To comply with w3c test suite expectation, create an empty media query
11403        // even when it is syntactically incorrect.
11404        rule = StyleRuleMedia::create(MediaQuerySet::create(), emptyRules);
11405    } else
11406        rule = StyleRuleMedia::create(media, rules ? *rules : emptyRules);
11407    processAndAddNewRuleToSourceTreeIfNeeded();
11408    return rule.release();
11409}
11410
11411PassRefPtr<StyleRuleBase> CSSParser::createEmptyMediaRule(RuleList* rules)
11412{
11413    return createMediaRule(MediaQuerySet::create(), rules);
11414}
11415
11416#if ENABLE(CSS3_CONDITIONAL_RULES)
11417PassRefPtr<StyleRuleBase> CSSParser::createSupportsRule(bool conditionIsSupported, RuleList* rules)
11418{
11419    m_allowImportRules = m_allowNamespaceDeclarations = false;
11420
11421    RefPtr<CSSRuleSourceData> data = popSupportsRuleData();
11422    RefPtr<StyleRuleSupports> rule;
11423    String conditionText;
11424    unsigned conditionOffset = data->ruleHeaderRange.start + 9;
11425    unsigned conditionLength = data->ruleHeaderRange.length() - 9;
11426
11427    if (is8BitSource())
11428        conditionText = String(m_dataStart8.get() + conditionOffset, conditionLength).stripWhiteSpace();
11429    else
11430        conditionText = String(m_dataStart16.get() + conditionOffset, conditionLength).stripWhiteSpace();
11431
11432    if (rules)
11433        rule = StyleRuleSupports::create(conditionText, conditionIsSupported, *rules);
11434    else {
11435        RuleList emptyRules;
11436        rule = StyleRuleSupports::create(conditionText, conditionIsSupported, emptyRules);
11437    }
11438
11439    processAndAddNewRuleToSourceTreeIfNeeded();
11440
11441    return rule.release();
11442}
11443
11444void CSSParser::markSupportsRuleHeaderStart()
11445{
11446    if (!m_supportsRuleDataStack)
11447        m_supportsRuleDataStack = std::make_unique<RuleSourceDataList>();
11448
11449    RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(CSSRuleSourceData::SUPPORTS_RULE);
11450    data->ruleHeaderRange.start = tokenStartOffset();
11451    m_supportsRuleDataStack->append(data);
11452}
11453
11454void CSSParser::markSupportsRuleHeaderEnd()
11455{
11456    ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
11457
11458    if (is8BitSource())
11459        m_supportsRuleDataStack->last()->ruleHeaderRange.end = tokenStart<LChar>() - m_dataStart8.get();
11460    else
11461        m_supportsRuleDataStack->last()->ruleHeaderRange.end = tokenStart<UChar>() - m_dataStart16.get();
11462}
11463
11464PassRefPtr<CSSRuleSourceData> CSSParser::popSupportsRuleData()
11465{
11466    ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
11467    RefPtr<CSSRuleSourceData> data = m_supportsRuleDataStack->last();
11468    m_supportsRuleDataStack->removeLast();
11469    return data.release();
11470}
11471
11472#endif
11473
11474void CSSParser::processAndAddNewRuleToSourceTreeIfNeeded()
11475{
11476    if (!isExtractingSourceData())
11477        return;
11478    markRuleBodyEnd();
11479    RefPtr<CSSRuleSourceData> rule = popRuleData();
11480    fixUnparsedPropertyRanges(rule.get());
11481    addNewRuleToSourceTree(rule.release());
11482}
11483
11484void CSSParser::addNewRuleToSourceTree(PassRefPtr<CSSRuleSourceData> rule)
11485{
11486    // Precondition: (isExtractingSourceData()).
11487    if (!m_ruleSourceDataResult)
11488        return;
11489    if (m_currentRuleDataStack->isEmpty())
11490        m_ruleSourceDataResult->append(rule);
11491    else
11492        m_currentRuleDataStack->last()->childRules.append(rule);
11493}
11494
11495PassRefPtr<CSSRuleSourceData> CSSParser::popRuleData()
11496{
11497    if (!m_ruleSourceDataResult)
11498        return 0;
11499
11500    ASSERT(!m_currentRuleDataStack->isEmpty());
11501    m_currentRuleData.clear();
11502    RefPtr<CSSRuleSourceData> data = m_currentRuleDataStack->last();
11503    m_currentRuleDataStack->removeLast();
11504    return data.release();
11505}
11506
11507void CSSParser::syntaxError(const Location& location, SyntaxErrorType error)
11508{
11509    if (!isLoggingErrors())
11510        return;
11511    StringBuilder builder;
11512    switch (error) {
11513    case PropertyDeclarationError:
11514        builder.appendLiteral("Invalid CSS property declaration at: ");
11515        break;
11516
11517    default:
11518        builder.appendLiteral("Unexpected CSS token: ");
11519    }
11520
11521    if (location.token.is8Bit())
11522        builder.append(location.token.characters8(), location.token.length());
11523    else
11524        builder.append(location.token.characters16(), location.token.length());
11525
11526    logError(builder.toString(), location.lineNumber);
11527
11528    m_ignoreErrorsInDeclaration = true;
11529}
11530
11531bool CSSParser::isLoggingErrors()
11532{
11533    return m_logErrors && !m_ignoreErrorsInDeclaration;
11534}
11535
11536void CSSParser::logError(const String& message, int lineNumber)
11537{
11538    // FIXME: <http://webkit.org/b/114313> CSS parser console message errors should include column numbers.
11539    PageConsole& console = m_styleSheet->singleOwnerDocument()->page()->console();
11540    console.addMessage(MessageSource::CSS, MessageLevel::Warning, message, m_styleSheet->baseURL().string(), lineNumber + 1, 0);
11541}
11542
11543PassRefPtr<StyleRuleKeyframes> CSSParser::createKeyframesRule(const String& name, std::unique_ptr<Vector<RefPtr<StyleKeyframe>>> popKeyframes)
11544{
11545    std::unique_ptr<Vector<RefPtr<StyleKeyframe>>> keyframes = WTF::move(popKeyframes);
11546    m_allowImportRules = m_allowNamespaceDeclarations = false;
11547    RefPtr<StyleRuleKeyframes> rule = StyleRuleKeyframes::create();
11548    for (size_t i = 0; i < keyframes->size(); ++i)
11549        rule->parserAppendKeyframe(keyframes->at(i));
11550    rule->setName(name);
11551    processAndAddNewRuleToSourceTreeIfNeeded();
11552    return rule.release();
11553}
11554
11555PassRefPtr<StyleRuleBase> CSSParser::createStyleRule(Vector<std::unique_ptr<CSSParserSelector>>* selectors)
11556{
11557    RefPtr<StyleRule> rule;
11558    if (selectors) {
11559        m_allowImportRules = false;
11560        m_allowNamespaceDeclarations = false;
11561        if (m_hasFontFaceOnlyValues)
11562            deleteFontFaceOnlyValues();
11563        rule = StyleRule::create(m_lastSelectorLineNumber, createStyleProperties());
11564        rule->parserAdoptSelectorVector(*selectors);
11565        processAndAddNewRuleToSourceTreeIfNeeded();
11566    } else
11567        popRuleData();
11568    clearProperties();
11569    return rule.release();
11570}
11571
11572PassRefPtr<StyleRuleBase> CSSParser::createFontFaceRule()
11573{
11574    m_allowImportRules = m_allowNamespaceDeclarations = false;
11575    for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
11576        CSSProperty& property = m_parsedProperties[i];
11577        if (property.id() == CSSPropertyFontVariant && property.value()->isPrimitiveValue())
11578            property.wrapValueInCommaSeparatedList();
11579        else if (property.id() == CSSPropertyFontFamily && (!property.value()->isValueList() || toCSSValueList(property.value())->length() != 1)) {
11580            // Unlike font-family property, font-family descriptor in @font-face rule
11581            // has to be a value list with exactly one family name. It cannot have a
11582            // have 'initial' value and cannot 'inherit' from parent.
11583            // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
11584            clearProperties();
11585            popRuleData();
11586            return 0;
11587        }
11588    }
11589    RefPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create(createStyleProperties());
11590    clearProperties();
11591    processAndAddNewRuleToSourceTreeIfNeeded();
11592    return rule.release();
11593}
11594
11595void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
11596{
11597    if (!m_styleSheet || !m_allowNamespaceDeclarations)
11598        return;
11599    m_allowImportRules = false;
11600    m_styleSheet->parserAddNamespace(prefix, uri);
11601    if (prefix.isEmpty() && !uri.isNull())
11602        m_defaultNamespace = uri;
11603}
11604
11605QualifiedName CSSParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName)
11606{
11607    if (!m_styleSheet)
11608        return QualifiedName(prefix, localName, m_defaultNamespace);
11609    return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix));
11610}
11611
11612void CSSParser::rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector& specifiers)
11613{
11614    if (m_defaultNamespace != starAtom || specifiers.isCustomPseudoElement())
11615        rewriteSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true);
11616}
11617
11618void CSSParser::rewriteSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector& specifiers, bool tagIsForNamespaceRule)
11619{
11620    AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
11621    QualifiedName tag(namespacePrefix, elementName, determinedNamespace);
11622
11623    if (!specifiers.isCustomPseudoElement()) {
11624        if (tag == anyQName())
11625            return;
11626        if (!specifiers.isPseudoElementCueFunction())
11627            specifiers.prependTagSelector(tag, tagIsForNamespaceRule);
11628        return;
11629    }
11630
11631    CSSParserSelector* lastShadowDescendant = &specifiers;
11632    CSSParserSelector* history = &specifiers;
11633    while (history->tagHistory()) {
11634        history = history->tagHistory();
11635        if (history->isCustomPseudoElement() || history->hasShadowDescendant())
11636            lastShadowDescendant = history;
11637    }
11638
11639    if (lastShadowDescendant->tagHistory()) {
11640        if (tag != anyQName())
11641            lastShadowDescendant->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
11642        return;
11643    }
11644
11645    // For shadow-ID pseudo-elements to be correctly matched, the ShadowDescendant combinator has to be used.
11646    // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
11647    lastShadowDescendant->setTagHistory(std::make_unique<CSSParserSelector>(tag));
11648    lastShadowDescendant->setRelation(CSSSelector::ShadowDescendant);
11649}
11650
11651std::unique_ptr<CSSParserSelector> CSSParser::rewriteSpecifiers(std::unique_ptr<CSSParserSelector> specifiers, std::unique_ptr<CSSParserSelector> newSpecifier)
11652{
11653    if (newSpecifier->isCustomPseudoElement() || newSpecifier->isPseudoElementCueFunction()) {
11654        // Unknown pseudo element always goes at the top of selector chain.
11655        newSpecifier->appendTagHistory(CSSSelector::ShadowDescendant, WTF::move(specifiers));
11656        return newSpecifier;
11657    }
11658    if (specifiers->isCustomPseudoElement()) {
11659        // Specifiers for unknown pseudo element go right behind it in the chain.
11660        specifiers->insertTagHistory(CSSSelector::SubSelector, WTF::move(newSpecifier), CSSSelector::ShadowDescendant);
11661        return specifiers;
11662    }
11663    specifiers->appendTagHistory(CSSSelector::SubSelector, WTF::move(newSpecifier));
11664    return specifiers;
11665}
11666
11667PassRefPtr<StyleRuleBase> CSSParser::createPageRule(std::unique_ptr<CSSParserSelector> pageSelector)
11668{
11669    // FIXME: Margin at-rules are ignored.
11670    m_allowImportRules = m_allowNamespaceDeclarations = false;
11671    RefPtr<StyleRulePage> rule;
11672    if (pageSelector) {
11673        rule = StyleRulePage::create(createStyleProperties());
11674        Vector<std::unique_ptr<CSSParserSelector>> selectorVector;
11675        selectorVector.append(WTF::move(pageSelector));
11676        rule->parserAdoptSelectorVector(selectorVector);
11677        processAndAddNewRuleToSourceTreeIfNeeded();
11678    } else
11679        popRuleData();
11680    clearProperties();
11681    return rule.release();
11682}
11683
11684std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> CSSParser::createSelectorVector()
11685{
11686    if (m_recycledSelectorVector) {
11687        m_recycledSelectorVector->shrink(0);
11688        return WTF::move(m_recycledSelectorVector);
11689    }
11690    return std::make_unique<Vector<std::unique_ptr<CSSParserSelector>>>();
11691}
11692
11693void CSSParser::recycleSelectorVector(std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> vector)
11694{
11695    if (vector && !m_recycledSelectorVector)
11696        m_recycledSelectorVector = WTF::move(vector);
11697}
11698
11699PassRefPtr<StyleRuleBase> CSSParser::createRegionRule(Vector<std::unique_ptr<CSSParserSelector>>* regionSelector, RuleList* rules)
11700{
11701    if (!cssRegionsEnabled() || !regionSelector || !rules) {
11702        popRuleData();
11703        return 0;
11704    }
11705
11706    m_allowImportRules = m_allowNamespaceDeclarations = false;
11707
11708    RefPtr<StyleRuleRegion> regionRule = StyleRuleRegion::create(regionSelector, *rules);
11709
11710    if (isExtractingSourceData())
11711        addNewRuleToSourceTree(CSSRuleSourceData::createUnknown());
11712
11713    return regionRule.release();
11714}
11715
11716void CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
11717{
11718    // FIXME: Implement margin at-rule here, using:
11719    //        - marginBox: margin box
11720    //        - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_parsedProperties.size()] are for this at-rule.
11721    // 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.
11722
11723    endDeclarationsForMarginBox();
11724}
11725
11726void CSSParser::startDeclarationsForMarginBox()
11727{
11728    m_numParsedPropertiesBeforeMarginBox = m_parsedProperties.size();
11729}
11730
11731void CSSParser::endDeclarationsForMarginBox()
11732{
11733    rollbackLastProperties(m_parsedProperties.size() - m_numParsedPropertiesBeforeMarginBox);
11734    m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
11735}
11736
11737void CSSParser::deleteFontFaceOnlyValues()
11738{
11739    ASSERT(m_hasFontFaceOnlyValues);
11740    for (unsigned i = 0; i < m_parsedProperties.size();) {
11741        CSSProperty& property = m_parsedProperties[i];
11742        if (property.id() == CSSPropertyFontVariant && property.value()->isValueList()) {
11743            m_parsedProperties.remove(i);
11744            continue;
11745        }
11746        ++i;
11747    }
11748}
11749
11750PassRefPtr<StyleKeyframe> CSSParser::createKeyframe(CSSParserValueList& keys)
11751{
11752    // Create a key string from the passed keys
11753    StringBuilder keyString;
11754    for (unsigned i = 0; i < keys.size(); ++i) {
11755        // Just as per the comment below, we ignore keyframes with
11756        // invalid key values (plain numbers or unknown identifiers)
11757        // marked as CSSPrimitiveValue::CSS_UNKNOWN during parsing.
11758        if (keys.valueAt(i)->unit == CSSPrimitiveValue::CSS_UNKNOWN) {
11759            clearProperties();
11760            return 0;
11761        }
11762
11763        ASSERT(keys.valueAt(i)->unit == CSSPrimitiveValue::CSS_NUMBER);
11764        float key = static_cast<float>(keys.valueAt(i)->fValue);
11765        if (key < 0 || key > 100) {
11766            // As per http://www.w3.org/TR/css3-animations/#keyframes,
11767            // "If a keyframe selector specifies negative percentage values
11768            // or values higher than 100%, then the keyframe will be ignored."
11769            clearProperties();
11770            return 0;
11771        }
11772        if (i != 0)
11773            keyString.append(',');
11774        keyString.appendNumber(key);
11775        keyString.append('%');
11776    }
11777
11778    RefPtr<StyleKeyframe> keyframe = StyleKeyframe::create(createStyleProperties());
11779    keyframe->setKeyText(keyString.toString());
11780
11781    clearProperties();
11782
11783    return keyframe.release();
11784}
11785
11786void CSSParser::invalidBlockHit()
11787{
11788    if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
11789        m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
11790}
11791
11792void CSSParser::updateLastSelectorLineAndPosition()
11793{
11794    m_lastSelectorLineNumber = m_lineNumber;
11795}
11796
11797void CSSParser::updateLastMediaLine(MediaQuerySet* media)
11798{
11799    media->setLastLine(m_lineNumber);
11800}
11801
11802template <typename CharacterType>
11803static inline void fixUnparsedProperties(const CharacterType* characters, CSSRuleSourceData* ruleData)
11804{
11805    Vector<CSSPropertySourceData>& propertyData = ruleData->styleSourceData->propertyData;
11806    unsigned size = propertyData.size();
11807    if (!size)
11808        return;
11809
11810    unsigned styleStart = ruleData->ruleBodyRange.start;
11811    CSSPropertySourceData* nextData = &(propertyData.at(0));
11812    for (unsigned i = 0; i < size; ++i) {
11813        CSSPropertySourceData* currentData = nextData;
11814        nextData = i < size - 1 ? &(propertyData.at(i + 1)) : 0;
11815
11816        if (currentData->parsedOk)
11817            continue;
11818        if (currentData->range.end > 0 && characters[styleStart + currentData->range.end - 1] == ';')
11819            continue;
11820
11821        unsigned propertyEndInStyleSheet;
11822        if (!nextData)
11823            propertyEndInStyleSheet = ruleData->ruleBodyRange.end - 1;
11824        else
11825            propertyEndInStyleSheet = styleStart + nextData->range.start - 1;
11826
11827        while (isHTMLSpace(characters[propertyEndInStyleSheet]))
11828            --propertyEndInStyleSheet;
11829
11830        // propertyEndInStyleSheet points at the last property text character.
11831        unsigned newPropertyEnd = propertyEndInStyleSheet - styleStart + 1; // Exclusive of the last property text character.
11832        if (currentData->range.end != newPropertyEnd) {
11833            currentData->range.end = newPropertyEnd;
11834            unsigned valueStartInStyleSheet = styleStart + currentData->range.start + currentData->name.length();
11835            while (valueStartInStyleSheet < propertyEndInStyleSheet && characters[valueStartInStyleSheet] != ':')
11836                ++valueStartInStyleSheet;
11837            if (valueStartInStyleSheet < propertyEndInStyleSheet)
11838                ++valueStartInStyleSheet; // Shift past the ':'.
11839            while (valueStartInStyleSheet < propertyEndInStyleSheet && isHTMLSpace(characters[valueStartInStyleSheet]))
11840                ++valueStartInStyleSheet;
11841            // Need to exclude the trailing ';' from the property value.
11842            currentData->value = String(characters + valueStartInStyleSheet, propertyEndInStyleSheet - valueStartInStyleSheet + (characters[propertyEndInStyleSheet] == ';' ? 0 : 1));
11843        }
11844    }
11845}
11846
11847void CSSParser::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData)
11848{
11849    if (!ruleData->styleSourceData)
11850        return;
11851
11852    if (is8BitSource()) {
11853        fixUnparsedProperties<LChar>(m_dataStart8.get() + m_parsedTextPrefixLength, ruleData);
11854        return;
11855    }
11856
11857    fixUnparsedProperties<UChar>(m_dataStart16.get() + m_parsedTextPrefixLength, ruleData);
11858}
11859
11860void CSSParser::markRuleHeaderStart(CSSRuleSourceData::Type ruleType)
11861{
11862    if (!isExtractingSourceData())
11863        return;
11864
11865    // Pop off data for a previous invalid rule.
11866    if (m_currentRuleData)
11867        m_currentRuleDataStack->removeLast();
11868
11869    RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(ruleType);
11870    data->ruleHeaderRange.start = tokenStartOffset();
11871    m_currentRuleData = data;
11872    m_currentRuleDataStack->append(data.release());
11873}
11874
11875template <typename CharacterType>
11876inline void CSSParser::setRuleHeaderEnd(const CharacterType* dataStart)
11877{
11878    CharacterType* listEnd = tokenStart<CharacterType>();
11879    while (listEnd > dataStart + 1) {
11880        if (isHTMLSpace(*(listEnd - 1)))
11881            --listEnd;
11882        else
11883            break;
11884    }
11885
11886    m_currentRuleDataStack->last()->ruleHeaderRange.end = listEnd - dataStart;
11887}
11888
11889void CSSParser::markRuleHeaderEnd()
11890{
11891    if (!isExtractingSourceData())
11892        return;
11893    ASSERT(!m_currentRuleDataStack->isEmpty());
11894
11895    if (is8BitSource())
11896        setRuleHeaderEnd<LChar>(m_dataStart8.get());
11897    else
11898        setRuleHeaderEnd<UChar>(m_dataStart16.get());
11899}
11900
11901void CSSParser::markSelectorStart()
11902{
11903    if (!isExtractingSourceData())
11904        return;
11905    ASSERT(!m_selectorRange.end);
11906
11907    m_selectorRange.start = tokenStartOffset();
11908}
11909
11910void CSSParser::markSelectorEnd()
11911{
11912    if (!isExtractingSourceData())
11913        return;
11914    ASSERT(!m_selectorRange.end);
11915    ASSERT(m_currentRuleDataStack->size());
11916
11917    m_selectorRange.end = tokenStartOffset();
11918    m_currentRuleDataStack->last()->selectorRanges.append(m_selectorRange);
11919    m_selectorRange.start = 0;
11920    m_selectorRange.end = 0;
11921}
11922
11923void CSSParser::markRuleBodyStart()
11924{
11925    if (!isExtractingSourceData())
11926        return;
11927    m_currentRuleData.clear();
11928    unsigned offset = tokenStartOffset();
11929    if (tokenStartChar() == '{')
11930        ++offset; // Skip the rule body opening brace.
11931    ASSERT(!m_currentRuleDataStack->isEmpty());
11932    m_currentRuleDataStack->last()->ruleBodyRange.start = offset;
11933}
11934
11935void CSSParser::markRuleBodyEnd()
11936{
11937    // Precondition: (!isExtractingSourceData())
11938    unsigned offset = tokenStartOffset();
11939    ASSERT(!m_currentRuleDataStack->isEmpty());
11940    m_currentRuleDataStack->last()->ruleBodyRange.end = offset;
11941}
11942
11943void CSSParser::markPropertyStart()
11944{
11945    m_ignoreErrorsInDeclaration = false;
11946    if (!isExtractingSourceData())
11947        return;
11948    if (m_currentRuleDataStack->isEmpty() || !m_currentRuleDataStack->last()->styleSourceData)
11949        return;
11950
11951    m_propertyRange.start = tokenStartOffset();
11952}
11953
11954void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed)
11955{
11956    if (!isExtractingSourceData())
11957        return;
11958    if (m_currentRuleDataStack->isEmpty() || !m_currentRuleDataStack->last()->styleSourceData)
11959        return;
11960
11961    unsigned offset = tokenStartOffset();
11962    if (tokenStartChar() == ';') // Include semicolon into the property text.
11963        ++offset;
11964    m_propertyRange.end = offset;
11965    if (m_propertyRange.start != UINT_MAX && !m_currentRuleDataStack->isEmpty()) {
11966        // This stuff is only executed when the style data retrieval is requested by client.
11967        const unsigned start = m_propertyRange.start;
11968        const unsigned end = m_propertyRange.end;
11969        ASSERT_WITH_SECURITY_IMPLICATION(start < end);
11970        String propertyString;
11971        if (is8BitSource())
11972            propertyString = String(m_dataStart8.get() + start, end - start).stripWhiteSpace();
11973        else
11974            propertyString = String(m_dataStart16.get() + start, end - start).stripWhiteSpace();
11975        if (propertyString.endsWith(';'))
11976            propertyString = propertyString.left(propertyString.length() - 1);
11977        size_t colonIndex = propertyString.find(':');
11978        ASSERT(colonIndex != notFound);
11979
11980        String name = propertyString.left(colonIndex).stripWhiteSpace();
11981        String value = propertyString.substring(colonIndex + 1, propertyString.length()).stripWhiteSpace();
11982        // The property range is relative to the declaration start offset.
11983        SourceRange& topRuleBodyRange = m_currentRuleDataStack->last()->ruleBodyRange;
11984        m_currentRuleDataStack->last()->styleSourceData->propertyData.append(
11985            CSSPropertySourceData(name, value, isImportantFound, isPropertyParsed, SourceRange(start - topRuleBodyRange.start, end - topRuleBodyRange.start)));
11986    }
11987    resetPropertyRange();
11988}
11989
11990#if ENABLE(CSS_DEVICE_ADAPTATION)
11991PassRefPtr<StyleRuleBase> CSSParser::createViewportRule()
11992{
11993    m_allowImportRules = m_allowNamespaceDeclarations = false;
11994
11995    RefPtr<StyleRuleViewport> rule = StyleRuleViewport::create(createStyleProperties());
11996    clearProperties();
11997
11998    processAndAddNewRuleToSourceTreeIfNeeded();
11999
12000    return rule.release();
12001}
12002
12003bool CSSParser::parseViewportProperty(CSSPropertyID propId, bool important)
12004{
12005    CSSParserValue* value = m_valueList->current();
12006    if (!value)
12007        return false;
12008
12009    CSSValueID id = value->id;
12010    bool validPrimitive = false;
12011
12012    switch (propId) {
12013    case CSSPropertyMinWidth: // auto | device-width | device-height | <length> | <percentage>
12014    case CSSPropertyMaxWidth:
12015    case CSSPropertyMinHeight:
12016    case CSSPropertyMaxHeight:
12017        if (id == CSSValueAuto || id == CSSValueDeviceWidth || id == CSSValueDeviceHeight)
12018            validPrimitive = true;
12019        else
12020            validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
12021        break;
12022    case CSSPropertyWidth: // shorthand
12023        return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMaxWidth, important);
12024    case CSSPropertyHeight:
12025        return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyMaxHeight, important);
12026    case CSSPropertyMinZoom: // auto | <number> | <percentage>
12027    case CSSPropertyMaxZoom:
12028    case CSSPropertyZoom:
12029        if (id == CSSValueAuto)
12030            validPrimitive = true;
12031        else
12032            validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg));
12033        break;
12034    case CSSPropertyUserZoom: // zoom | fixed
12035        if (id == CSSValueZoom || id == CSSValueFixed)
12036            validPrimitive = true;
12037        break;
12038    case CSSPropertyOrientation: // auto | portrait | landscape
12039        if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandscape)
12040            validPrimitive = true;
12041    default:
12042        break;
12043    }
12044
12045    RefPtr<CSSValue> parsedValue;
12046    if (validPrimitive) {
12047        parsedValue = parseValidPrimitive(id, value);
12048        m_valueList->next();
12049    }
12050
12051    if (parsedValue) {
12052        if (!m_valueList->current() || inShorthand()) {
12053            addProperty(propId, parsedValue.release(), important);
12054            return true;
12055        }
12056    }
12057
12058    return false;
12059}
12060
12061bool CSSParser::parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first, CSSPropertyID second, bool important)
12062{
12063    unsigned numValues = m_valueList->size();
12064
12065    if (numValues > 2)
12066        return false;
12067
12068    ShorthandScope scope(this, propId);
12069
12070    if (!parseViewportProperty(first, important))
12071        return false;
12072
12073    // If just one value is supplied, the second value
12074    // is implicitly initialized with the first value.
12075    if (numValues == 1)
12076        m_valueList->previous();
12077
12078    return parseViewportProperty(second, important);
12079}
12080#endif
12081
12082template <typename CharacterType>
12083static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
12084{
12085    char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
12086
12087    for (unsigned i = 0; i != length; ++i) {
12088        CharacterType c = propertyName[i];
12089        if (c == 0 || c >= 0x7F)
12090            return CSSPropertyInvalid; // illegal character
12091        buffer[i] = toASCIILower(c);
12092    }
12093    buffer[length] = '\0';
12094
12095    const char* name = buffer;
12096    if (buffer[0] == '-') {
12097#if ENABLE(LEGACY_CSS_VENDOR_PREFIXES)
12098        // If the prefix is -apple- or -khtml-, change it to -webkit-.
12099        // This makes the string one character longer.
12100        if (RuntimeEnabledFeatures::sharedFeatures().legacyCSSVendorPrefixesEnabled()
12101            && (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-"))) {
12102            memmove(buffer + 7, buffer + 6, length + 1 - 6);
12103            memcpy(buffer, "-webkit", 7);
12104            ++length;
12105        }
12106#endif
12107#if PLATFORM(IOS)
12108        cssPropertyNameIOSAliasing(buffer, name, length);
12109#endif
12110    }
12111
12112    const Property* hashTableEntry = findProperty(name, length);
12113    return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
12114}
12115
12116CSSPropertyID cssPropertyID(const String& string)
12117{
12118    unsigned length = string.length();
12119
12120    if (!length)
12121        return CSSPropertyInvalid;
12122    if (length > maxCSSPropertyNameLength)
12123        return CSSPropertyInvalid;
12124
12125    return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
12126}
12127
12128CSSPropertyID cssPropertyID(const CSSParserString& string)
12129{
12130    unsigned length = string.length();
12131
12132    if (!length)
12133        return CSSPropertyInvalid;
12134    if (length > maxCSSPropertyNameLength)
12135        return CSSPropertyInvalid;
12136
12137    return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
12138}
12139
12140#if PLATFORM(IOS)
12141void cssPropertyNameIOSAliasing(const char* propertyName, const char*& propertyNameAlias, unsigned& newLength)
12142{
12143    if (!strcmp(propertyName, "-webkit-hyphenate-locale")) {
12144        // Worked in iOS 4.2.
12145        static const char* const webkitLocale = "-webkit-locale";
12146        propertyNameAlias = webkitLocale;
12147        newLength = strlen(webkitLocale);
12148    }
12149}
12150#endif
12151
12152template <typename CharacterType>
12153static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
12154{
12155    char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
12156
12157    for (unsigned i = 0; i != length; ++i) {
12158        CharacterType c = valueKeyword[i];
12159        if (c == 0 || c >= 0x7F)
12160            return CSSValueInvalid; // illegal keyword.
12161        buffer[i] = WTF::toASCIILower(c);
12162    }
12163    buffer[length] = '\0';
12164
12165    if (buffer[0] == '-') {
12166        // If the prefix is -apple- or -khtml-, change it to -webkit-.
12167        // This makes the string one character longer.
12168        // On iOS we don't want to change values starting with -apple-system to -webkit-system.
12169        if ((hasPrefix(buffer, length, "-apple-") && !hasPrefix(buffer, length, "-apple-system")) || hasPrefix(buffer, length, "-khtml-")) {
12170            memmove(buffer + 7, buffer + 6, length + 1 - 6);
12171            memcpy(buffer, "-webkit", 7);
12172            ++length;
12173        }
12174    }
12175
12176    const Value* hashTableEntry = findValue(buffer, length);
12177    return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSValueInvalid;
12178}
12179
12180CSSValueID cssValueKeywordID(const CSSParserString& string)
12181{
12182    unsigned length = string.length();
12183    if (!length)
12184        return CSSValueInvalid;
12185    if (length > maxCSSValueKeywordLength)
12186        return CSSValueInvalid;
12187
12188    return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
12189}
12190
12191template <typename CharacterType>
12192static inline bool isCSSTokenizerIdentifier(const CharacterType* characters, unsigned length)
12193{
12194    const CharacterType* end = characters + length;
12195
12196    // -?
12197    if (characters != end && characters[0] == '-')
12198        ++characters;
12199
12200    // {nmstart}
12201    if (characters == end || !(characters[0] == '_' || characters[0] >= 128 || isASCIIAlpha(characters[0])))
12202        return false;
12203    ++characters;
12204
12205    // {nmchar}*
12206    for (; characters != end; ++characters) {
12207        if (!(characters[0] == '_' || characters[0] == '-' || characters[0] >= 128 || isASCIIAlphanumeric(characters[0])))
12208            return false;
12209    }
12210
12211    return true;
12212}
12213
12214// "ident" from the CSS tokenizer, minus backslash-escape sequences
12215static bool isCSSTokenizerIdentifier(const String& string)
12216{
12217    unsigned length = string.length();
12218
12219    if (!length)
12220        return false;
12221
12222    if (string.is8Bit())
12223        return isCSSTokenizerIdentifier(string.characters8(), length);
12224    return isCSSTokenizerIdentifier(string.characters16(), length);
12225}
12226
12227template <typename CharacterType>
12228static inline bool isCSSTokenizerURL(const CharacterType* characters, unsigned length)
12229{
12230    const CharacterType* end = characters + length;
12231
12232    for (; characters != end; ++characters) {
12233        CharacterType c = characters[0];
12234        switch (c) {
12235            case '!':
12236            case '#':
12237            case '$':
12238            case '%':
12239            case '&':
12240                break;
12241            default:
12242                if (c < '*')
12243                    return false;
12244                if (c <= '~')
12245                    break;
12246                if (c < 128)
12247                    return false;
12248        }
12249    }
12250
12251    return true;
12252}
12253
12254// "url" from the CSS tokenizer, minus backslash-escape sequences
12255static bool isCSSTokenizerURL(const String& string)
12256{
12257    unsigned length = string.length();
12258
12259    if (!length)
12260        return true;
12261
12262    if (string.is8Bit())
12263        return isCSSTokenizerURL(string.characters8(), length);
12264    return isCSSTokenizerURL(string.characters16(), length);
12265}
12266
12267
12268template <typename CharacterType>
12269static inline String quoteCSSStringInternal(const CharacterType* characters, unsigned length)
12270{
12271    // For efficiency, we first pre-calculate the length of the quoted string, then we build the actual one.
12272    // Please see below for the actual logic.
12273    unsigned quotedStringSize = 2; // Two quotes surrounding the entire string.
12274    bool afterEscape = false;
12275    for (unsigned i = 0; i < length; ++i) {
12276        CharacterType ch = characters[i];
12277        if (ch == '\\' || ch == '\'') {
12278            quotedStringSize += 2;
12279            afterEscape = false;
12280        } else if (ch < 0x20 || ch == 0x7F) {
12281            quotedStringSize += 2 + (ch >= 0x10);
12282            afterEscape = true;
12283        } else {
12284            quotedStringSize += 1 + (afterEscape && (isASCIIHexDigit(ch) || ch == ' '));
12285            afterEscape = false;
12286        }
12287    }
12288
12289    StringBuffer<CharacterType> buffer(quotedStringSize);
12290    unsigned index = 0;
12291    buffer[index++] = '\'';
12292    afterEscape = false;
12293    for (unsigned i = 0; i < length; ++i) {
12294        CharacterType ch = characters[i];
12295        if (ch == '\\' || ch == '\'') {
12296            buffer[index++] = '\\';
12297            buffer[index++] = ch;
12298            afterEscape = false;
12299        } else if (ch < 0x20 || ch == 0x7F) { // Control characters.
12300            buffer[index++] = '\\';
12301            placeByteAsHexCompressIfPossible(ch, buffer, index, Lowercase);
12302            afterEscape = true;
12303        } else {
12304            // Space character may be required to separate backslash-escape sequence and normal characters.
12305            if (afterEscape && (isASCIIHexDigit(ch) || ch == ' '))
12306                buffer[index++] = ' ';
12307            buffer[index++] = ch;
12308            afterEscape = false;
12309        }
12310    }
12311    buffer[index++] = '\'';
12312
12313    ASSERT(quotedStringSize == index);
12314    return String::adopt(buffer);
12315}
12316
12317// We use single quotes for now because markup.cpp uses double quotes.
12318String quoteCSSString(const String& string)
12319{
12320    // This function expands each character to at most 3 characters ('\u0010' -> '\' '1' '0') as well as adds
12321    // 2 quote characters (before and after). Make sure the resulting size (3 * length + 2) will not overflow unsigned.
12322
12323    unsigned length = string.length();
12324
12325    if (!length)
12326        return String("\'\'");
12327
12328    if (length > std::numeric_limits<unsigned>::max() / 3 - 2)
12329        return emptyString();
12330
12331    if (string.is8Bit())
12332        return quoteCSSStringInternal(string.characters8(), length);
12333    return quoteCSSStringInternal(string.characters16(), length);
12334}
12335
12336String quoteCSSStringIfNeeded(const String& string)
12337{
12338    return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string);
12339}
12340
12341String quoteCSSURLIfNeeded(const String& string)
12342{
12343    return isCSSTokenizerURL(string) ? string : quoteCSSString(string);
12344}
12345
12346bool isValidNthToken(const CSSParserString& token)
12347{
12348    // The tokenizer checks for the construct of an+b.
12349    // However, since the {ident} rule precedes the {nth} rule, some of those
12350    // tokens are identified as string literal. Furthermore we need to accept
12351    // "odd" and "even" which does not match to an+b.
12352    return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
12353        || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");
12354}
12355
12356}
12357