1/*
2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
6 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
7 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
9 * Copyright (C) 2012 Intel Corporation. All rights reserved.
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 * Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB.  If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
25 */
26
27#include "config.h"
28#include "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 "CSSFontFaceRule.h"
37#include "CSSFontFaceSrcValue.h"
38#include "CSSFunctionValue.h"
39#include "CSSGradientValue.h"
40#include "CSSImageValue.h"
41#include "CSSInheritedValue.h"
42#include "CSSInitialValue.h"
43#include "CSSLineBoxContainValue.h"
44#include "CSSMediaRule.h"
45#include "CSSPageRule.h"
46#include "CSSPrimitiveValue.h"
47#include "CSSPropertySourceData.h"
48#include "CSSReflectValue.h"
49#include "CSSSelector.h"
50#include "CSSStyleSheet.h"
51#include "CSSTimingFunctionValue.h"
52#include "CSSUnicodeRangeValue.h"
53#include "CSSValueKeywords.h"
54#include "CSSValueList.h"
55#include "CSSValuePool.h"
56#if ENABLE(CSS_VARIABLES)
57#include "CSSVariableValue.h"
58#endif
59#include "Counter.h"
60#include "Document.h"
61#include "FloatConversion.h"
62#include "FontFeatureValue.h"
63#include "FontValue.h"
64#include "HTMLParserIdioms.h"
65#include "HashTools.h"
66#include "HistogramSupport.h"
67#include "MediaList.h"
68#include "MediaQueryExp.h"
69#include "Page.h"
70#include "PageConsole.h"
71#include "Pair.h"
72#include "Rect.h"
73#include "RenderTheme.h"
74#include "RuntimeEnabledFeatures.h"
75#include "SVGParserUtilities.h"
76#include "Settings.h"
77#include "ShadowValue.h"
78#include "StylePropertySet.h"
79#include "StylePropertyShorthand.h"
80#include "StyleRule.h"
81#include "StyleRuleImport.h"
82#include "StyleSheetContents.h"
83#include "TextEncoding.h"
84#include "WebKitCSSKeyframeRule.h"
85#include "WebKitCSSKeyframesRule.h"
86#include "WebKitCSSRegionRule.h"
87#include "WebKitCSSTransformValue.h"
88#include <limits.h>
89#include <wtf/BitArray.h>
90#include <wtf/HexNumber.h>
91#include <wtf/dtoa.h>
92#include <wtf/text/StringBuffer.h>
93#include <wtf/text/StringBuilder.h>
94#include <wtf/text/StringImpl.h>
95
96#if ENABLE(CSS_IMAGE_SET)
97#include "CSSImageSetValue.h"
98#endif
99
100#if ENABLE(CSS_FILTERS)
101#include "WebKitCSSFilterValue.h"
102#if ENABLE(SVG)
103#include "WebKitCSSSVGDocumentValue.h"
104#endif
105#endif
106
107#if ENABLE(CSS_SHADERS)
108#include "WebKitCSSArrayFunctionValue.h"
109#include "WebKitCSSMatFunctionValue.h"
110#include "WebKitCSSMixFunctionValue.h"
111#include "WebKitCSSShaderValue.h"
112#endif
113
114#if ENABLE(DASHBOARD_SUPPORT)
115#include "DashboardRegion.h"
116#endif
117
118#define YYDEBUG 0
119
120#if YYDEBUG > 0
121extern int cssyydebug;
122#endif
123
124extern int cssyyparse(WebCore::CSSParser*);
125
126using namespace std;
127using namespace WTF;
128
129namespace {
130
131enum PropertyType {
132    PropertyExplicit,
133    PropertyImplicit
134};
135
136class ImplicitScope {
137    WTF_MAKE_NONCOPYABLE(ImplicitScope);
138public:
139    ImplicitScope(WebCore::CSSParser* parser, PropertyType propertyType)
140        : m_parser(parser)
141    {
142        m_parser->m_implicitShorthand = propertyType == PropertyImplicit;
143    }
144
145    ~ImplicitScope()
146    {
147        m_parser->m_implicitShorthand = false;
148    }
149
150private:
151    WebCore::CSSParser* m_parser;
152};
153
154} // namespace
155
156namespace WebCore {
157
158static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
159static const double MAX_SCALE = 1000000;
160
161template <unsigned N>
162static bool equal(const CSSParserString& a, const char (&b)[N])
163{
164    unsigned length = N - 1; // Ignore the trailing null character
165    if (a.length() != length)
166        return false;
167
168    return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar*>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length);
169}
170
171template <unsigned N>
172static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
173{
174    unsigned length = N - 1; // Ignore the trailing null character
175    if (a.length() != length)
176        return false;
177
178    return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length);
179}
180
181template <unsigned N>
182static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N])
183{
184    ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrimitiveValue::CSS_STRING);
185    return equalIgnoringCase(value->string, b);
186}
187
188static bool hasPrefix(const char* string, unsigned length, const char* prefix)
189{
190    for (unsigned i = 0; i < length; ++i) {
191        if (!prefix[i])
192            return true;
193        if (string[i] != prefix[i])
194            return false;
195    }
196    return false;
197}
198
199static PassRefPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtr<CSSPrimitiveValue> first, PassRefPtr<CSSPrimitiveValue> second)
200{
201    return cssValuePool().createValue(Pair::create(first, second));
202}
203
204class AnimationParseContext {
205public:
206    AnimationParseContext()
207        : m_animationPropertyKeywordAllowed(true)
208        , m_firstAnimationCommitted(false)
209        , m_hasSeenAnimationPropertyKeyword(false)
210    {
211    }
212
213    void commitFirstAnimation()
214    {
215        m_firstAnimationCommitted = true;
216    }
217
218    bool hasCommittedFirstAnimation() const
219    {
220        return m_firstAnimationCommitted;
221    }
222
223    void commitAnimationPropertyKeyword()
224    {
225        m_animationPropertyKeywordAllowed = false;
226    }
227
228    bool animationPropertyKeywordAllowed() const
229    {
230        return m_animationPropertyKeywordAllowed;
231    }
232
233    bool hasSeenAnimationPropertyKeyword() const
234    {
235        return m_hasSeenAnimationPropertyKeyword;
236    }
237
238    void sawAnimationPropertyKeyword()
239    {
240        m_hasSeenAnimationPropertyKeyword = true;
241    }
242
243private:
244    bool m_animationPropertyKeywordAllowed;
245    bool m_firstAnimationCommitted;
246    bool m_hasSeenAnimationPropertyKeyword;
247};
248
249const CSSParserContext& strictCSSParserContext()
250{
251    DEFINE_STATIC_LOCAL(CSSParserContext, strictContext, (CSSStrictMode));
252    return strictContext;
253}
254
255CSSParserContext::CSSParserContext(CSSParserMode mode, const KURL& baseURL)
256    : baseURL(baseURL)
257    , mode(mode)
258    , isHTMLDocument(false)
259    , isCSSCustomFilterEnabled(false)
260    , isCSSStickyPositionEnabled(false)
261    , isCSSRegionsEnabled(false)
262    , isCSSCompositingEnabled(false)
263    , isCSSGridLayoutEnabled(false)
264#if ENABLE(CSS_VARIABLES)
265    , isCSSVariablesEnabled(false)
266#endif
267    , needsSiteSpecificQuirks(false)
268    , enforcesCSSMIMETypeInNoQuirksMode(true)
269    , useLegacyBackgroundSizeShorthandBehavior(false)
270{
271}
272
273CSSParserContext::CSSParserContext(Document* document, const KURL& baseURL, const String& charset)
274    : baseURL(baseURL.isNull() ? document->baseURL() : baseURL)
275    , charset(charset)
276    , mode(document->inQuirksMode() ? CSSQuirksMode : CSSStrictMode)
277    , isHTMLDocument(document->isHTMLDocument())
278    , isCSSCustomFilterEnabled(document->settings() ? document->settings()->isCSSCustomFilterEnabled() : false)
279    , isCSSStickyPositionEnabled(document->cssStickyPositionEnabled())
280    , isCSSRegionsEnabled(document->cssRegionsEnabled())
281    , isCSSCompositingEnabled(document->cssCompositingEnabled())
282    , isCSSGridLayoutEnabled(document->cssGridLayoutEnabled())
283#if ENABLE(CSS_VARIABLES)
284    , isCSSVariablesEnabled(document->settings() ? document->settings()->cssVariablesEnabled() : false)
285#endif
286    , needsSiteSpecificQuirks(document->settings() ? document->settings()->needsSiteSpecificQuirks() : false)
287    , enforcesCSSMIMETypeInNoQuirksMode(!document->settings() || document->settings()->enforceCSSMIMETypeInNoQuirksMode())
288    , useLegacyBackgroundSizeShorthandBehavior(document->settings() ? document->settings()->useLegacyBackgroundSizeShorthandBehavior() : false)
289{
290}
291
292bool operator==(const CSSParserContext& a, const CSSParserContext& b)
293{
294    return a.baseURL == b.baseURL
295        && a.charset == b.charset
296        && a.mode == b.mode
297        && a.isHTMLDocument == b.isHTMLDocument
298        && a.isCSSCustomFilterEnabled == b.isCSSCustomFilterEnabled
299        && a.isCSSStickyPositionEnabled == b.isCSSStickyPositionEnabled
300        && a.isCSSRegionsEnabled == b.isCSSRegionsEnabled
301        && a.isCSSCompositingEnabled == b.isCSSCompositingEnabled
302        && a.isCSSGridLayoutEnabled == b.isCSSGridLayoutEnabled
303#if ENABLE(CSS_VARIABLES)
304        && a.isCSSVariablesEnabled == b.isCSSVariablesEnabled
305#endif
306        && a.needsSiteSpecificQuirks == b.needsSiteSpecificQuirks
307        && a.enforcesCSSMIMETypeInNoQuirksMode == b.enforcesCSSMIMETypeInNoQuirksMode
308        && a.useLegacyBackgroundSizeShorthandBehavior == b.useLegacyBackgroundSizeShorthandBehavior;
309}
310
311CSSParser::CSSParser(const CSSParserContext& context)
312    : m_context(context)
313    , m_important(false)
314    , m_id(CSSPropertyInvalid)
315    , m_styleSheet(0)
316#if ENABLE(CSS3_CONDITIONAL_RULES)
317    , m_supportsCondition(false)
318#endif
319    , m_selectorListForParseSelector(0)
320    , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
321    , m_inParseShorthand(0)
322    , m_currentShorthand(CSSPropertyInvalid)
323    , m_implicitShorthand(false)
324    , m_hasFontFaceOnlyValues(false)
325    , m_hadSyntacticallyValidCSSRule(false)
326    , m_logErrors(false)
327    , m_ignoreErrorsInDeclaration(false)
328#if ENABLE(CSS_SHADERS)
329    , m_inFilterRule(false)
330#endif
331    , m_defaultNamespace(starAtom)
332    , m_parsedTextPrefixLength(0)
333    , m_propertyRange(UINT_MAX, UINT_MAX)
334    , m_ruleSourceDataResult(0)
335    , m_parsingMode(NormalMode)
336    , m_is8BitSource(false)
337    , m_currentCharacter8(0)
338    , m_currentCharacter16(0)
339    , m_length(0)
340    , m_token(0)
341    , m_lineNumber(0)
342    , m_tokenStartLineNumber(0)
343    , m_lastSelectorLineNumber(0)
344    , m_allowImportRules(true)
345    , m_allowNamespaceDeclarations(true)
346#if ENABLE(CSS_DEVICE_ADAPTATION)
347    , m_inViewport(false)
348#endif
349{
350#if YYDEBUG > 0
351    cssyydebug = 1;
352#endif
353    m_tokenStart.ptr8 = 0;
354}
355
356CSSParser::~CSSParser()
357{
358    clearProperties();
359
360    deleteAllValues(m_floatingSelectors);
361    deleteAllValues(m_floatingSelectorVectors);
362    deleteAllValues(m_floatingValueLists);
363    deleteAllValues(m_floatingFunctions);
364}
365
366template <typename CharacterType>
367ALWAYS_INLINE static void makeLower(const CharacterType* input, CharacterType* output, unsigned length)
368{
369    // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
370    // that can potentially change the length of the string rather than the character
371    // by character kind. If we don't need Unicode lowercasing, it would be good to
372    // simplify this function.
373
374    if (charactersAreAllASCII(input, length)) {
375        // Fast case for all-ASCII.
376        for (unsigned i = 0; i < length; i++)
377            output[i] = toASCIILower(input[i]);
378    } else {
379        for (unsigned i = 0; i < length; i++)
380            output[i] = Unicode::toLower(input[i]);
381    }
382}
383
384void CSSParserString::lower()
385{
386    if (is8Bit()) {
387        makeLower(characters8(), characters8(), length());
388        return;
389    }
390
391    makeLower(characters16(), characters16(), length());
392}
393
394#if ENABLE(CSS_VARIABLES)
395AtomicString CSSParserString::substring(unsigned position, unsigned length) const
396{
397    ASSERT(m_length >= position + length);
398
399    if (is8Bit())
400        return AtomicString(characters8() + position, length);
401    return AtomicString(characters16() + position, length);
402}
403#endif
404
405void CSSParser::setupParser(const char* prefix, unsigned prefixLength, const String& string, const char* suffix, unsigned suffixLength)
406{
407    m_parsedTextPrefixLength = prefixLength;
408    unsigned stringLength = string.length();
409    unsigned length = stringLength + m_parsedTextPrefixLength + suffixLength + 1;
410    m_length = length;
411
412    if (!stringLength || string.is8Bit()) {
413        m_dataStart8 = adoptArrayPtr(new LChar[length]);
414        for (unsigned i = 0; i < m_parsedTextPrefixLength; i++)
415            m_dataStart8[i] = prefix[i];
416
417        if (stringLength)
418            memcpy(m_dataStart8.get() + m_parsedTextPrefixLength, string.characters8(), stringLength * sizeof(LChar));
419
420        unsigned start = m_parsedTextPrefixLength + stringLength;
421        unsigned end = start + suffixLength;
422        for (unsigned i = start; i < end; i++)
423            m_dataStart8[i] = suffix[i - start];
424
425        m_dataStart8[length - 1] = 0;
426
427        m_is8BitSource = true;
428        m_currentCharacter8 = m_dataStart8.get();
429        m_currentCharacter16 = 0;
430        setTokenStart<LChar>(m_currentCharacter8);
431        m_lexFunc = &CSSParser::realLex<LChar>;
432        return;
433    }
434
435    m_dataStart16 = adoptArrayPtr(new UChar[length]);
436    for (unsigned i = 0; i < m_parsedTextPrefixLength; i++)
437        m_dataStart16[i] = prefix[i];
438
439    memcpy(m_dataStart16.get() + m_parsedTextPrefixLength, string.characters(), stringLength * sizeof(UChar));
440
441    unsigned start = m_parsedTextPrefixLength + stringLength;
442    unsigned end = start + suffixLength;
443    for (unsigned i = start; i < end; i++)
444        m_dataStart16[i] = suffix[i - start];
445
446    m_dataStart16[length - 1] = 0;
447
448    m_is8BitSource = false;
449    m_currentCharacter8 = 0;
450    m_currentCharacter16 = m_dataStart16.get();
451    setTokenStart<UChar>(m_currentCharacter16);
452    m_lexFunc = &CSSParser::realLex<UChar>;
453}
454
455void CSSParser::parseSheet(StyleSheetContents* sheet, const String& string, int startLineNumber, RuleSourceDataList* ruleSourceDataResult, bool logErrors)
456{
457    setStyleSheet(sheet);
458    m_defaultNamespace = starAtom; // Reset the default namespace.
459    if (ruleSourceDataResult)
460        m_currentRuleDataStack = adoptPtr(new RuleSourceDataList());
461    m_ruleSourceDataResult = ruleSourceDataResult;
462
463    m_logErrors = logErrors && sheet->singleOwnerDocument() && !sheet->baseURL().isEmpty() && sheet->singleOwnerDocument()->page();
464    m_ignoreErrorsInDeclaration = false;
465    m_lineNumber = startLineNumber;
466    setupParser("", string, "");
467    cssyyparse(this);
468    sheet->shrinkToFit();
469    m_currentRuleDataStack.clear();
470    m_ruleSourceDataResult = 0;
471    m_rule = 0;
472    m_ignoreErrorsInDeclaration = false;
473    m_logErrors = false;
474}
475
476PassRefPtr<StyleRuleBase> CSSParser::parseRule(StyleSheetContents* sheet, const String& string)
477{
478    setStyleSheet(sheet);
479    m_allowNamespaceDeclarations = false;
480    setupParser("@-webkit-rule{", string, "} ");
481    cssyyparse(this);
482    return m_rule.release();
483}
484
485PassRefPtr<StyleKeyframe> CSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string)
486{
487    setStyleSheet(sheet);
488    setupParser("@-webkit-keyframe-rule{ ", string, "} ");
489    cssyyparse(this);
490    return m_keyframe.release();
491}
492
493#if ENABLE(CSS3_CONDITIONAL_RULES)
494bool CSSParser::parseSupportsCondition(const String& string)
495{
496    m_supportsCondition = false;
497    setupParser("@-webkit-supports-condition{ ", string, "} ");
498    cssyyparse(this);
499    return m_supportsCondition;
500}
501#endif
502
503static inline bool isColorPropertyID(CSSPropertyID propertyId)
504{
505    switch (propertyId) {
506    case CSSPropertyColor:
507    case CSSPropertyBackgroundColor:
508    case CSSPropertyBorderBottomColor:
509    case CSSPropertyBorderLeftColor:
510    case CSSPropertyBorderRightColor:
511    case CSSPropertyBorderTopColor:
512    case CSSPropertyOutlineColor:
513    case CSSPropertyTextLineThroughColor:
514    case CSSPropertyTextOverlineColor:
515    case CSSPropertyTextUnderlineColor:
516    case CSSPropertyWebkitBorderAfterColor:
517    case CSSPropertyWebkitBorderBeforeColor:
518    case CSSPropertyWebkitBorderEndColor:
519    case CSSPropertyWebkitBorderStartColor:
520    case CSSPropertyWebkitColumnRuleColor:
521#if ENABLE(CSS3_TEXT)
522    case CSSPropertyWebkitTextDecorationColor:
523#endif // CSS3_TEXT
524    case CSSPropertyWebkitTextEmphasisColor:
525    case CSSPropertyWebkitTextFillColor:
526    case CSSPropertyWebkitTextStrokeColor:
527        return true;
528    default:
529        return false;
530    }
531}
532
533static bool parseColorValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
534{
535    ASSERT(!string.isEmpty());
536    bool strict = isStrictParserMode(cssParserMode);
537    if (!isColorPropertyID(propertyId))
538        return false;
539    CSSParserString cssString;
540    cssString.init(string);
541    int valueID = cssValueKeywordID(cssString);
542    bool validPrimitive = false;
543    if (valueID == CSSValueWebkitText)
544        validPrimitive = true;
545    else if (valueID == CSSValueCurrentcolor)
546        validPrimitive = true;
547    else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
548             || (valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText && !strict)) {
549        validPrimitive = true;
550    }
551
552    if (validPrimitive) {
553        RefPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID);
554        declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
555        return true;
556    }
557    RGBA32 color;
558    if (!CSSParser::fastParseColor(color, string, strict && string[0] != '#'))
559        return false;
560    RefPtr<CSSValue> value = cssValuePool().createColorValue(color);
561    declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
562    return true;
563}
564
565static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
566{
567    switch (propertyId) {
568    case CSSPropertyFontSize:
569    case CSSPropertyHeight:
570    case CSSPropertyWidth:
571    case CSSPropertyMinHeight:
572    case CSSPropertyMinWidth:
573    case CSSPropertyPaddingBottom:
574    case CSSPropertyPaddingLeft:
575    case CSSPropertyPaddingRight:
576    case CSSPropertyPaddingTop:
577    case CSSPropertyWebkitLogicalWidth:
578    case CSSPropertyWebkitLogicalHeight:
579    case CSSPropertyWebkitMinLogicalWidth:
580    case CSSPropertyWebkitMinLogicalHeight:
581    case CSSPropertyWebkitPaddingAfter:
582    case CSSPropertyWebkitPaddingBefore:
583    case CSSPropertyWebkitPaddingEnd:
584    case CSSPropertyWebkitPaddingStart:
585        acceptsNegativeNumbers = false;
586        return true;
587#if ENABLE(CSS_SHAPES)
588    case CSSPropertyWebkitShapeMargin:
589    case CSSPropertyWebkitShapePadding:
590        acceptsNegativeNumbers = false;
591        return RuntimeEnabledFeatures::cssShapesEnabled();
592#endif
593    case CSSPropertyBottom:
594    case CSSPropertyLeft:
595    case CSSPropertyMarginBottom:
596    case CSSPropertyMarginLeft:
597    case CSSPropertyMarginRight:
598    case CSSPropertyMarginTop:
599    case CSSPropertyRight:
600    case CSSPropertyTop:
601    case CSSPropertyWebkitMarginAfter:
602    case CSSPropertyWebkitMarginBefore:
603    case CSSPropertyWebkitMarginEnd:
604    case CSSPropertyWebkitMarginStart:
605        acceptsNegativeNumbers = true;
606        return true;
607    default:
608        return false;
609    }
610}
611
612template <typename CharacterType>
613static inline bool parseSimpleLength(const CharacterType* characters, unsigned& length, CSSPrimitiveValue::UnitTypes& unit, double& number)
614{
615    if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
616        length -= 2;
617        unit = CSSPrimitiveValue::CSS_PX;
618    } else if (length > 1 && characters[length - 1] == '%') {
619        length -= 1;
620        unit = CSSPrimitiveValue::CSS_PERCENTAGE;
621    }
622
623    // We rely on charactersToDouble for validation as well. The function
624    // will set "ok" to "false" if the entire passed-in character range does
625    // not represent a double.
626    bool ok;
627    number = charactersToDouble(characters, length, &ok);
628    return ok;
629}
630
631static bool parseSimpleLengthValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
632{
633    ASSERT(!string.isEmpty());
634    bool acceptsNegativeNumbers;
635    if (!isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
636        return false;
637
638    unsigned length = string.length();
639    double number;
640    CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
641
642    if (string.is8Bit()) {
643        if (!parseSimpleLength(string.characters8(), length, unit, number))
644            return false;
645    } else {
646        if (!parseSimpleLength(string.characters16(), length, unit, number))
647            return false;
648    }
649
650    if (unit == CSSPrimitiveValue::CSS_NUMBER) {
651        if (number && isStrictParserMode(cssParserMode))
652            return false;
653        unit = CSSPrimitiveValue::CSS_PX;
654    }
655    if (number < 0 && !acceptsNegativeNumbers)
656        return false;
657
658    RefPtr<CSSValue> value = cssValuePool().createValue(number, unit);
659    declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
660    return true;
661}
662
663static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext)
664{
665    if (!valueID)
666        return false;
667
668    switch (propertyId) {
669    case CSSPropertyBorderCollapse: // collapse | separate | inherit
670        if (valueID == CSSValueCollapse || valueID == CSSValueSeparate)
671            return true;
672        break;
673    case CSSPropertyBorderTopStyle: // <border-style> | inherit
674    case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
675    case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
676    case CSSPropertyBorderLeftStyle:
677    case CSSPropertyWebkitBorderAfterStyle:
678    case CSSPropertyWebkitBorderBeforeStyle:
679    case CSSPropertyWebkitBorderEndStyle:
680    case CSSPropertyWebkitBorderStartStyle:
681    case CSSPropertyWebkitColumnRuleStyle:
682        if (valueID >= CSSValueNone && valueID <= CSSValueDouble)
683            return true;
684        break;
685    case CSSPropertyBoxSizing:
686         if (valueID == CSSValueBorderBox || valueID == CSSValueContentBox)
687             return true;
688         break;
689    case CSSPropertyCaptionSide: // top | bottom | left | right | inherit
690        if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom)
691            return true;
692        break;
693    case CSSPropertyClear: // none | left | right | both | inherit
694        if (valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth)
695            return true;
696        break;
697    case CSSPropertyDirection: // ltr | rtl | inherit
698        if (valueID == CSSValueLtr || valueID == CSSValueRtl)
699            return true;
700        break;
701    case CSSPropertyDisplay:
702        // inline | block | list-item | run-in | inline-block | table |
703        // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
704        // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none | inherit
705        // -webkit-flex | -webkit-inline-flex | -webkit-grid | -webkit-inline-grid
706        if ((valueID >= CSSValueInline && valueID <= CSSValueWebkitInlineFlex) || valueID == CSSValueNone)
707            return true;
708        if (parserContext.isCSSGridLayoutEnabled && (valueID == CSSValueWebkitGrid || valueID == CSSValueWebkitInlineGrid))
709            return true;
710        break;
711
712    case CSSPropertyEmptyCells: // show | hide | inherit
713        if (valueID == CSSValueShow || valueID == CSSValueHide)
714            return true;
715        break;
716    case CSSPropertyFloat: // left | right | none | center (for buggy CSS, maps to none)
717        if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone || valueID == CSSValueCenter)
718            return true;
719        break;
720    case CSSPropertyFontStyle: // normal | italic | oblique | inherit
721        if (valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique)
722            return true;
723        break;
724    case CSSPropertyImageRendering: // auto | optimizeSpeed | optimizeQuality | -webkit-crisp-edges | -webkit-optimize-contrast
725        if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizequality
726            || valueID == CSSValueWebkitCrispEdges || valueID == CSSValueWebkitOptimizeContrast)
727            return true;
728        break;
729    case CSSPropertyListStylePosition: // inside | outside | inherit
730        if (valueID == CSSValueInside || valueID == CSSValueOutside)
731            return true;
732        break;
733    case CSSPropertyListStyleType:
734        // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
735        // for the list of supported list-style-types.
736        if ((valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone)
737            return true;
738        break;
739    case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit
740        if (valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble))
741            return true;
742        break;
743    case CSSPropertyOverflowWrap: // normal | break-word
744    case CSSPropertyWordWrap:
745        if (valueID == CSSValueNormal || valueID == CSSValueBreakWord)
746            return true;
747        break;
748    case CSSPropertyOverflowX: // visible | hidden | scroll | auto | marquee | overlay | inherit
749        if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitMarquee)
750            return true;
751        break;
752    case CSSPropertyOverflowY: // visible | hidden | scroll | auto | marquee | overlay | inherit | -webkit-paged-x | -webkit-paged-y
753        if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitMarquee || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY)
754            return true;
755        break;
756    case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit
757    case CSSPropertyPageBreakBefore:
758    case CSSPropertyWebkitColumnBreakAfter:
759    case CSSPropertyWebkitColumnBreakBefore:
760        if (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight)
761            return true;
762        break;
763    case CSSPropertyPageBreakInside: // avoid | auto | inherit
764    case CSSPropertyWebkitColumnBreakInside:
765        if (valueID == CSSValueAuto || valueID == CSSValueAvoid)
766            return true;
767        break;
768    case CSSPropertyPointerEvents:
769        // none | visiblePainted | visibleFill | visibleStroke | visible |
770        // painted | fill | stroke | auto | all | inherit
771        if (valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueStroke))
772            return true;
773        break;
774    case CSSPropertyPosition: // static | relative | absolute | fixed | sticky | inherit
775        if (valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed
776#if ENABLE(CSS_STICKY_POSITION)
777            || (parserContext.isCSSStickyPositionEnabled && valueID == CSSValueWebkitSticky)
778#endif
779            )
780            return true;
781        break;
782    case CSSPropertyResize: // none | both | horizontal | vertical | auto
783        if (valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto)
784            return true;
785        break;
786    case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit
787        if (valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation)
788            return true;
789        break;
790    case CSSPropertyTableLayout: // auto | fixed | inherit
791        if (valueID == CSSValueAuto || valueID == CSSValueFixed)
792            return true;
793        break;
794    case CSSPropertyTextLineThroughMode:
795    case CSSPropertyTextOverlineMode:
796    case CSSPropertyTextUnderlineMode:
797        if (valueID == CSSValueContinuous || valueID == CSSValueSkipWhiteSpace)
798            return true;
799        break;
800    case CSSPropertyTextLineThroughStyle:
801    case CSSPropertyTextOverlineStyle:
802    case CSSPropertyTextUnderlineStyle:
803        if (valueID == CSSValueNone || valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDashed || valueID == CSSValueDotDash || valueID == CSSValueDotDotDash || valueID == CSSValueWave)
804            return true;
805        break;
806    case CSSPropertyTextOverflow: // clip | ellipsis
807        if (valueID == CSSValueClip || valueID == CSSValueEllipsis)
808            return true;
809        break;
810    case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
811        if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision)
812            return true;
813        break;
814    case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit
815        if ((valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone)
816            return true;
817        break;
818    case CSSPropertyVisibility: // visible | hidden | collapse | inherit
819        if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse)
820            return true;
821        break;
822    case CSSPropertyWebkitAppearance:
823        if ((valueID >= CSSValueCheckbox && valueID <= CSSValueTextarea) || valueID == CSSValueNone)
824            return true;
825        break;
826    case CSSPropertyWebkitBackfaceVisibility:
827        if (valueID == CSSValueVisible || valueID == CSSValueHidden)
828            return true;
829        break;
830#if ENABLE(CSS_COMPOSITING)
831    case CSSPropertyWebkitBlendMode:
832        if (parserContext.isCSSCompositingEnabled && (valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen
833            || valueID == CSSValueOverlay || valueID == CSSValueDarken || valueID == CSSValueLighten ||  valueID == CSSValueColorDodge
834            || valueID == CSSValueColorBurn || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference
835            || valueID == CSSValueExclusion || valueID == CSSValueHue || valueID == CSSValueSaturation || valueID == CSSValueColor
836            || valueID == CSSValueLuminosity))
837            return true;
838        break;
839#endif
840    case CSSPropertyWebkitBorderFit:
841        if (valueID == CSSValueBorder || valueID == CSSValueLines)
842            return true;
843        break;
844    case CSSPropertyWebkitBoxAlign:
845        if (valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline)
846            return true;
847        break;
848#if ENABLE(CSS_BOX_DECORATION_BREAK)
849    case CSSPropertyWebkitBoxDecorationBreak:
850         if (valueID == CSSValueClone || valueID == CSSValueSlice)
851             return true;
852         break;
853#endif
854    case CSSPropertyWebkitBoxDirection:
855        if (valueID == CSSValueNormal || valueID == CSSValueReverse)
856            return true;
857        break;
858    case CSSPropertyWebkitBoxLines:
859        if (valueID == CSSValueSingle || valueID == CSSValueMultiple)
860                return true;
861        break;
862    case CSSPropertyWebkitBoxOrient:
863        if (valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis)
864            return true;
865        break;
866    case CSSPropertyWebkitBoxPack:
867        if (valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify)
868            return true;
869        break;
870    case CSSPropertyWebkitColorCorrection:
871        if (valueID == CSSValueSrgb || valueID == CSSValueDefault)
872            return true;
873        break;
874    case CSSPropertyWebkitAlignContent:
875         if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch)
876             return true;
877         break;
878    case CSSPropertyWebkitAlignItems:
879        if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
880            return true;
881        break;
882    case CSSPropertyWebkitAlignSelf:
883        if (valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
884            return true;
885        break;
886    case CSSPropertyWebkitFlexDirection:
887        if (valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse)
888            return true;
889        break;
890    case CSSPropertyWebkitFlexWrap:
891        if (valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse)
892             return true;
893        break;
894    case CSSPropertyWebkitJustifyContent:
895        if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround)
896            return true;
897        break;
898    case CSSPropertyWebkitFontKerning:
899        if (valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone)
900            return true;
901        break;
902    case CSSPropertyWebkitFontSmoothing:
903        if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased)
904            return true;
905        break;
906    case CSSPropertyWebkitHyphens:
907        if (valueID == CSSValueNone || valueID == CSSValueManual || valueID == CSSValueAuto)
908            return true;
909        break;
910    case CSSPropertyWebkitGridAutoFlow:
911        if (valueID == CSSValueNone || valueID == CSSValueRow || valueID == CSSValueColumn)
912            return true;
913        break;
914    case CSSPropertyWebkitLineAlign:
915        if (valueID == CSSValueNone || valueID == CSSValueEdges)
916            return true;
917        break;
918    case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
919        if (valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace)
920            return true;
921        break;
922    case CSSPropertyWebkitLineSnap:
923        if (valueID == CSSValueNone || valueID == CSSValueBaseline || valueID == CSSValueContain)
924            return true;
925        break;
926    case CSSPropertyWebkitMarginAfterCollapse:
927    case CSSPropertyWebkitMarginBeforeCollapse:
928    case CSSPropertyWebkitMarginBottomCollapse:
929    case CSSPropertyWebkitMarginTopCollapse:
930        if (valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard)
931            return true;
932        break;
933    case CSSPropertyWebkitMarqueeDirection:
934        if (valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
935            || valueID == CSSValueUp || valueID == CSSValueAuto)
936            return true;
937        break;
938    case CSSPropertyWebkitMarqueeStyle:
939        if (valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate)
940            return true;
941        break;
942    case CSSPropertyWebkitNbspMode: // normal | space
943        if (valueID == CSSValueNormal || valueID == CSSValueSpace)
944            return true;
945        break;
946#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
947    case CSSPropertyWebkitOverflowScrolling:
948        if (valueID == CSSValueAuto || valueID == CSSValueTouch)
949            return true;
950        break;
951#endif
952    case CSSPropertyWebkitPrintColorAdjust:
953        if (valueID == CSSValueExact || valueID == CSSValueEconomy)
954            return true;
955        break;
956#if ENABLE(CSS_REGIONS)
957    case CSSPropertyWebkitRegionBreakAfter:
958    case CSSPropertyWebkitRegionBreakBefore:
959        if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight))
960            return true;
961        break;
962    case CSSPropertyWebkitRegionBreakInside:
963        if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueAvoid))
964            return true;
965        break;
966    case CSSPropertyWebkitRegionFragment:
967        if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueBreak))
968            return true;
969        break;
970#endif
971    case CSSPropertyWebkitRtlOrdering:
972        if (valueID == CSSValueLogical || valueID == CSSValueVisual)
973            return true;
974        break;
975
976    case CSSPropertyWebkitRubyPosition:
977        if (valueID == CSSValueBefore || valueID == CSSValueAfter)
978            return true;
979        break;
980
981#if ENABLE(CSS3_TEXT)
982    case CSSPropertyWebkitTextAlignLast:
983        // auto | start | end | left | right | center | justify
984        if ((valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto)
985            return true;
986        break;
987#endif // CSS3_TEXT
988    case CSSPropertyWebkitTextCombine:
989        if (valueID == CSSValueNone || valueID == CSSValueHorizontal)
990            return true;
991        break;
992    case CSSPropertyWebkitTextEmphasisPosition:
993        if (valueID == CSSValueOver || valueID == CSSValueUnder)
994            return true;
995        break;
996#if ENABLE(CSS3_TEXT)
997    case CSSPropertyWebkitTextJustify:
998        // auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida
999        if ((valueID >= CSSValueInterWord && valueID <= CSSValueKashida) || valueID == CSSValueAuto || valueID == CSSValueNone)
1000            return true;
1001        break;
1002#endif // CSS3_TEXT
1003    case CSSPropertyWebkitTextSecurity:
1004        // disc | circle | square | none | inherit
1005        if (valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone)
1006            return true;
1007        break;
1008    case CSSPropertyWebkitTransformStyle:
1009        if (valueID == CSSValueFlat || valueID == CSSValuePreserve3d)
1010            return true;
1011        break;
1012    case CSSPropertyWebkitUserDrag: // auto | none | element
1013        if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement)
1014            return true;
1015        break;
1016    case CSSPropertyWebkitUserModify: // read-only | read-write
1017        if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly)
1018            return true;
1019        break;
1020    case CSSPropertyWebkitUserSelect: // auto | none | text | all
1021        if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll)
1022            return true;
1023        break;
1024#if ENABLE(CSS_EXCLUSIONS)
1025    case CSSPropertyWebkitWrapFlow:
1026        if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
1027            return false;
1028        if (valueID == CSSValueAuto || valueID == CSSValueBoth || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueMaximum || valueID == CSSValueClear)
1029            return true;
1030        break;
1031    case CSSPropertyWebkitWrapThrough:
1032        if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
1033            return false;
1034        if (valueID == CSSValueWrap || valueID == CSSValueNone)
1035            return true;
1036        break;
1037#endif
1038    case CSSPropertyWebkitWritingMode:
1039        if (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
1040            return true;
1041        break;
1042    case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit
1043        if (valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap)
1044            return true;
1045        break;
1046    case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
1047        if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord)
1048            return true;
1049        break;
1050    default:
1051        ASSERT_NOT_REACHED();
1052        return false;
1053    }
1054    return false;
1055}
1056
1057static inline bool isKeywordPropertyID(CSSPropertyID propertyId)
1058{
1059    switch (propertyId) {
1060    case CSSPropertyBorderBottomStyle:
1061    case CSSPropertyBorderCollapse:
1062    case CSSPropertyBorderLeftStyle:
1063    case CSSPropertyBorderRightStyle:
1064    case CSSPropertyBorderTopStyle:
1065    case CSSPropertyBoxSizing:
1066    case CSSPropertyCaptionSide:
1067    case CSSPropertyClear:
1068    case CSSPropertyDirection:
1069    case CSSPropertyDisplay:
1070    case CSSPropertyEmptyCells:
1071    case CSSPropertyFloat:
1072    case CSSPropertyFontStyle:
1073    case CSSPropertyImageRendering:
1074    case CSSPropertyListStylePosition:
1075    case CSSPropertyListStyleType:
1076    case CSSPropertyOutlineStyle:
1077    case CSSPropertyOverflowWrap:
1078    case CSSPropertyOverflowX:
1079    case CSSPropertyOverflowY:
1080    case CSSPropertyPageBreakAfter:
1081    case CSSPropertyPageBreakBefore:
1082    case CSSPropertyPageBreakInside:
1083    case CSSPropertyPointerEvents:
1084    case CSSPropertyPosition:
1085    case CSSPropertyResize:
1086    case CSSPropertySpeak:
1087    case CSSPropertyTableLayout:
1088    case CSSPropertyTextLineThroughMode:
1089    case CSSPropertyTextLineThroughStyle:
1090    case CSSPropertyTextOverflow:
1091    case CSSPropertyTextOverlineMode:
1092    case CSSPropertyTextOverlineStyle:
1093    case CSSPropertyTextRendering:
1094    case CSSPropertyTextTransform:
1095    case CSSPropertyTextUnderlineMode:
1096    case CSSPropertyTextUnderlineStyle:
1097    case CSSPropertyVisibility:
1098    case CSSPropertyWebkitAppearance:
1099#if ENABLE(CSS_COMPOSITING)
1100    case CSSPropertyWebkitBlendMode:
1101#endif
1102    case CSSPropertyWebkitBackfaceVisibility:
1103    case CSSPropertyWebkitBorderAfterStyle:
1104    case CSSPropertyWebkitBorderBeforeStyle:
1105    case CSSPropertyWebkitBorderEndStyle:
1106    case CSSPropertyWebkitBorderFit:
1107    case CSSPropertyWebkitBorderStartStyle:
1108    case CSSPropertyWebkitBoxAlign:
1109#if ENABLE(CSS_BOX_DECORATION_BREAK)
1110    case CSSPropertyWebkitBoxDecorationBreak:
1111#endif
1112    case CSSPropertyWebkitBoxDirection:
1113    case CSSPropertyWebkitBoxLines:
1114    case CSSPropertyWebkitBoxOrient:
1115    case CSSPropertyWebkitBoxPack:
1116    case CSSPropertyWebkitColorCorrection:
1117    case CSSPropertyWebkitColumnBreakAfter:
1118    case CSSPropertyWebkitColumnBreakBefore:
1119    case CSSPropertyWebkitColumnBreakInside:
1120    case CSSPropertyWebkitColumnRuleStyle:
1121    case CSSPropertyWebkitAlignContent:
1122    case CSSPropertyWebkitAlignItems:
1123    case CSSPropertyWebkitAlignSelf:
1124    case CSSPropertyWebkitFlexDirection:
1125    case CSSPropertyWebkitFlexWrap:
1126    case CSSPropertyWebkitJustifyContent:
1127    case CSSPropertyWebkitFontKerning:
1128    case CSSPropertyWebkitFontSmoothing:
1129    case CSSPropertyWebkitHyphens:
1130    case CSSPropertyWebkitGridAutoFlow:
1131    case CSSPropertyWebkitLineAlign:
1132    case CSSPropertyWebkitLineBreak:
1133    case CSSPropertyWebkitLineSnap:
1134    case CSSPropertyWebkitMarginAfterCollapse:
1135    case CSSPropertyWebkitMarginBeforeCollapse:
1136    case CSSPropertyWebkitMarginBottomCollapse:
1137    case CSSPropertyWebkitMarginTopCollapse:
1138    case CSSPropertyWebkitMarqueeDirection:
1139    case CSSPropertyWebkitMarqueeStyle:
1140    case CSSPropertyWebkitNbspMode:
1141#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
1142    case CSSPropertyWebkitOverflowScrolling:
1143#endif
1144    case CSSPropertyWebkitPrintColorAdjust:
1145#if ENABLE(CSS_REGIONS)
1146    case CSSPropertyWebkitRegionBreakAfter:
1147    case CSSPropertyWebkitRegionBreakBefore:
1148    case CSSPropertyWebkitRegionBreakInside:
1149    case CSSPropertyWebkitRegionFragment:
1150#endif
1151    case CSSPropertyWebkitRtlOrdering:
1152    case CSSPropertyWebkitRubyPosition:
1153#if ENABLE(CSS3_TEXT)
1154    case CSSPropertyWebkitTextAlignLast:
1155#endif // CSS3_TEXT
1156    case CSSPropertyWebkitTextCombine:
1157    case CSSPropertyWebkitTextEmphasisPosition:
1158#if ENABLE(CSS3_TEXT)
1159    case CSSPropertyWebkitTextJustify:
1160#endif // CSS3_TEXT
1161    case CSSPropertyWebkitTextSecurity:
1162    case CSSPropertyWebkitTransformStyle:
1163    case CSSPropertyWebkitUserDrag:
1164    case CSSPropertyWebkitUserModify:
1165    case CSSPropertyWebkitUserSelect:
1166#if ENABLE(CSS_EXCLUSIONS)
1167    case CSSPropertyWebkitWrapFlow:
1168    case CSSPropertyWebkitWrapThrough:
1169#endif
1170    case CSSPropertyWebkitWritingMode:
1171    case CSSPropertyWhiteSpace:
1172    case CSSPropertyWordBreak:
1173    case CSSPropertyWordWrap:
1174        return true;
1175    default:
1176        return false;
1177    }
1178}
1179
1180static bool parseKeywordValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext)
1181{
1182    ASSERT(!string.isEmpty());
1183
1184    if (!isKeywordPropertyID(propertyId)) {
1185        // All properties accept the values of "initial" and "inherit".
1186        String lowerCaseString = string.lower();
1187        if (lowerCaseString != "initial" && lowerCaseString != "inherit")
1188            return false;
1189
1190        // Parse initial/inherit shorthands using the CSSParser.
1191        if (shorthandForProperty(propertyId).length())
1192            return false;
1193    }
1194
1195    CSSParserString cssString;
1196    cssString.init(string);
1197    int valueID = cssValueKeywordID(cssString);
1198
1199    if (!valueID)
1200        return false;
1201
1202    RefPtr<CSSValue> value;
1203    if (valueID == CSSValueInherit)
1204        value = cssValuePool().createInheritedValue();
1205    else if (valueID == CSSValueInitial)
1206        value = cssValuePool().createExplicitInitialValue();
1207    else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext))
1208        value = cssValuePool().createIdentifierValue(valueID);
1209    else
1210        return false;
1211
1212    declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
1213    return true;
1214}
1215
1216template <typename CharacterType>
1217static bool parseTransformArguments(WebKitCSSTransformValue* transformValue, CharacterType* characters, unsigned length, unsigned start, unsigned expectedCount)
1218{
1219    while (expectedCount) {
1220        size_t end = WTF::find(characters, length, expectedCount == 1 ? ')' : ',', start);
1221        if (end == notFound || (expectedCount == 1 && end != length - 1))
1222            return false;
1223        unsigned argumentLength = end - start;
1224        CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
1225        double number;
1226        if (!parseSimpleLength(characters + start, argumentLength, unit, number))
1227            return false;
1228        if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER))
1229            return false;
1230        transformValue->append(cssValuePool().createValue(number, unit));
1231        start = end + 1;
1232        --expectedCount;
1233    }
1234    return true;
1235}
1236
1237static bool parseTranslateTransformValue(MutableStylePropertySet* properties, CSSPropertyID propertyID, const String& string, bool important)
1238{
1239    if (propertyID != CSSPropertyWebkitTransform)
1240        return false;
1241    static const unsigned shortestValidTransformStringLength = 12;
1242    static const unsigned likelyMultipartTransformStringLengthCutoff = 32;
1243    if (string.length() < shortestValidTransformStringLength || string.length() > likelyMultipartTransformStringLengthCutoff)
1244        return false;
1245    if (!string.startsWith("translate", false))
1246        return false;
1247    UChar c9 = toASCIILower(string[9]);
1248    UChar c10 = toASCIILower(string[10]);
1249
1250    WebKitCSSTransformValue::TransformOperationType transformType;
1251    unsigned expectedArgumentCount = 1;
1252    unsigned argumentStart = 11;
1253    if (c9 == 'x' && c10 == '(')
1254        transformType = WebKitCSSTransformValue::TranslateXTransformOperation;
1255    else if (c9 == 'y' && c10 == '(')
1256        transformType = WebKitCSSTransformValue::TranslateYTransformOperation;
1257    else if (c9 == 'z' && c10 == '(')
1258        transformType = WebKitCSSTransformValue::TranslateZTransformOperation;
1259    else if (c9 == '(') {
1260        transformType = WebKitCSSTransformValue::TranslateTransformOperation;
1261        expectedArgumentCount = 2;
1262        argumentStart = 10;
1263    } else if (c9 == '3' && c10 == 'd' && string[11] == '(') {
1264        transformType = WebKitCSSTransformValue::Translate3DTransformOperation;
1265        expectedArgumentCount = 3;
1266        argumentStart = 12;
1267    } else
1268        return false;
1269
1270    RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(transformType);
1271    bool success;
1272    if (string.is8Bit())
1273        success = parseTransformArguments(transformValue.get(), string.characters8(), string.length(), argumentStart, expectedArgumentCount);
1274    else
1275        success = parseTransformArguments(transformValue.get(), string.characters16(), string.length(), argumentStart, expectedArgumentCount);
1276    if (!success)
1277        return false;
1278    RefPtr<CSSValueList> result = CSSValueList::createSpaceSeparated();
1279    result->append(transformValue.release());
1280    properties->addParsedProperty(CSSProperty(CSSPropertyWebkitTransform, result.release(), important));
1281    return true;
1282}
1283
1284PassRefPtr<CSSValueList> CSSParser::parseFontFaceValue(const AtomicString& string)
1285{
1286    if (string.isEmpty())
1287        return 0;
1288    RefPtr<MutableStylePropertySet> dummyStyle = MutableStylePropertySet::create();
1289    if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, CSSQuirksMode, 0))
1290        return 0;
1291
1292    RefPtr<CSSValue> fontFamily = dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily);
1293    if (!fontFamily->isValueList())
1294        return 0; // FIXME: "initial" and "inherit" should be parsed as font names in the face attribute.
1295    return static_pointer_cast<CSSValueList>(fontFamily.release());
1296}
1297
1298#if ENABLE(CSS_VARIABLES)
1299bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, Document* document)
1300{
1301    ASSERT(!string.isEmpty());
1302
1303    CSSParserContext context(document);
1304
1305    if (parseSimpleLengthValue(declaration, propertyID, string, important, context.mode))
1306        return true;
1307    if (parseColorValue(declaration, propertyID, string, important, context.mode))
1308        return true;
1309    if (parseKeywordValue(declaration, propertyID, string, important, context))
1310        return true;
1311
1312    CSSParser parser(context);
1313    return parser.parseValue(declaration, propertyID, string, important, static_cast<StyleSheetContents*>(0));
1314}
1315#endif
1316
1317bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
1318{
1319    ASSERT(!string.isEmpty());
1320    if (parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode))
1321        return true;
1322    if (parseColorValue(declaration, propertyID, string, important, cssParserMode))
1323        return true;
1324
1325    CSSParserContext context(cssParserMode);
1326    if (contextStyleSheet) {
1327        context = contextStyleSheet->parserContext();
1328        context.mode = cssParserMode;
1329    }
1330
1331    if (parseKeywordValue(declaration, propertyID, string, important, context))
1332        return true;
1333    if (parseTranslateTransformValue(declaration, propertyID, string, important))
1334        return true;
1335
1336    CSSParser parser(context);
1337    return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet);
1338}
1339
1340bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet)
1341{
1342    setStyleSheet(contextStyleSheet);
1343
1344    setupParser("@-webkit-value{", string, "} ");
1345
1346    m_id = propertyID;
1347    m_important = important;
1348
1349    cssyyparse(this);
1350
1351    m_rule = 0;
1352
1353    bool ok = false;
1354    if (m_hasFontFaceOnlyValues)
1355        deleteFontFaceOnlyValues();
1356    if (!m_parsedProperties.isEmpty()) {
1357        ok = true;
1358        declaration->addParsedProperties(m_parsedProperties);
1359        clearProperties();
1360    }
1361
1362    return ok;
1363}
1364
1365// The color will only be changed when string contains a valid CSS color, so callers
1366// can set it to a default color and ignore the boolean result.
1367bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
1368{
1369    // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
1370    if (fastParseColor(color, string, strict))
1371        return true;
1372
1373    CSSParser parser(CSSStrictMode);
1374
1375    // In case the fast-path parser didn't understand the color, try the full parser.
1376    if (!parser.parseColor(string))
1377        return false;
1378
1379    CSSValue* value = parser.m_parsedProperties.first().value();
1380    if (!value->isPrimitiveValue())
1381        return false;
1382
1383    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
1384    if (!primitiveValue->isRGBColor())
1385        return false;
1386
1387    color = primitiveValue->getRGBA32Value();
1388    return true;
1389}
1390
1391bool CSSParser::parseColor(const String& string)
1392{
1393    setupParser("@-webkit-decls{color:", string, "} ");
1394    cssyyparse(this);
1395    m_rule = 0;
1396
1397    return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor;
1398}
1399
1400bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document)
1401{
1402    if (!document || !document->page())
1403        return false;
1404
1405    CSSParserString cssColor;
1406    cssColor.init(string);
1407    int id = cssValueKeywordID(cssColor);
1408    if (id <= 0)
1409        return false;
1410
1411    color = document->page()->theme()->systemColor(id).rgb();
1412    return true;
1413}
1414
1415void CSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
1416{
1417    m_selectorListForParseSelector = &selectorList;
1418
1419    setupParser("@-webkit-selector{", string, "}");
1420
1421    cssyyparse(this);
1422
1423    m_selectorListForParseSelector = 0;
1424}
1425
1426PassRefPtr<ImmutableStylePropertySet> CSSParser::parseInlineStyleDeclaration(const String& string, Element* element)
1427{
1428    CSSParserContext context = element->document()->elementSheet()->contents()->parserContext();
1429    context.mode = strictToCSSParserMode(element->isHTMLElement() && !element->document()->inQuirksMode());
1430    return CSSParser(context).parseDeclaration(string, element->document()->elementSheet()->contents());
1431}
1432
1433PassRefPtr<ImmutableStylePropertySet> CSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet)
1434{
1435    setStyleSheet(contextStyleSheet);
1436
1437    setupParser("@-webkit-decls{", string, "} ");
1438    cssyyparse(this);
1439    m_rule = 0;
1440
1441    if (m_hasFontFaceOnlyValues)
1442        deleteFontFaceOnlyValues();
1443
1444    RefPtr<ImmutableStylePropertySet> style = createStylePropertySet();
1445    clearProperties();
1446    return style.release();
1447}
1448
1449
1450bool CSSParser::parseDeclaration(MutableStylePropertySet* declaration, const String& string, PassRefPtr<CSSRuleSourceData> prpRuleSourceData, StyleSheetContents* contextStyleSheet)
1451{
1452    // Length of the "@-webkit-decls{" prefix.
1453    static const unsigned prefixLength = 15;
1454
1455    setStyleSheet(contextStyleSheet);
1456
1457    RefPtr<CSSRuleSourceData> ruleSourceData = prpRuleSourceData;
1458    if (ruleSourceData) {
1459        m_currentRuleDataStack = adoptPtr(new RuleSourceDataList());
1460        m_currentRuleDataStack->append(ruleSourceData);
1461    }
1462
1463    setupParser("@-webkit-decls{", string, "} ");
1464    cssyyparse(this);
1465    m_rule = 0;
1466
1467    bool ok = false;
1468    if (m_hasFontFaceOnlyValues)
1469        deleteFontFaceOnlyValues();
1470    if (!m_parsedProperties.isEmpty()) {
1471        ok = true;
1472        declaration->addParsedProperties(m_parsedProperties);
1473        clearProperties();
1474    }
1475
1476    if (ruleSourceData) {
1477        ASSERT(m_currentRuleDataStack->size() == 1);
1478        ruleSourceData->ruleBodyRange.start = 0;
1479        ruleSourceData->ruleBodyRange.end = string.length();
1480        for (size_t i = 0, size = ruleSourceData->styleSourceData->propertyData.size(); i < size; ++i) {
1481            CSSPropertySourceData& propertyData = ruleSourceData->styleSourceData->propertyData.at(i);
1482            propertyData.range.start -= prefixLength;
1483            propertyData.range.end -= prefixLength;
1484        }
1485
1486        fixUnparsedPropertyRanges(ruleSourceData.get());
1487        m_currentRuleDataStack.clear();
1488    }
1489
1490    return ok;
1491}
1492
1493PassOwnPtr<MediaQuery> CSSParser::parseMediaQuery(const String& string)
1494{
1495    if (string.isEmpty())
1496        return nullptr;
1497
1498    ASSERT(!m_mediaQuery);
1499
1500    // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
1501    // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
1502    setupParser("@-webkit-mediaquery ", string, "} ");
1503    cssyyparse(this);
1504
1505    return m_mediaQuery.release();
1506}
1507
1508#if ENABLE(CSS_VARIABLES)
1509static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties, HashSet<AtomicString>& seenVariables)
1510#else
1511static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties)
1512#endif
1513{
1514    // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
1515    for (int i = input.size() - 1; i >= 0; --i) {
1516        const CSSProperty& property = input[i];
1517        if (property.isImportant() != important)
1518            continue;
1519#if ENABLE(CSS_VARIABLES)
1520        if (property.id() == CSSPropertyVariable) {
1521            const AtomicString& name = static_cast<CSSVariableValue*>(property.value())->name();
1522            if (seenVariables.contains(name))
1523                continue;
1524            seenVariables.add(name);
1525            output[--unusedEntries] = property;
1526            continue;
1527        }
1528#endif
1529        const unsigned propertyIDIndex = property.id() - firstCSSProperty;
1530        if (seenProperties.get(propertyIDIndex))
1531            continue;
1532        seenProperties.set(propertyIDIndex);
1533        output[--unusedEntries] = property;
1534    }
1535}
1536
1537PassRefPtr<ImmutableStylePropertySet> CSSParser::createStylePropertySet()
1538{
1539    BitArray<numCSSProperties> seenProperties;
1540    size_t unusedEntries = m_parsedProperties.size();
1541    Vector<CSSProperty, 256> results(unusedEntries);
1542
1543    // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found.
1544#if ENABLE(CSS_VARIABLES)
1545    HashSet<AtomicString> seenVariables;
1546    filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
1547    filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
1548#else
1549    filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties);
1550    filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties);
1551#endif
1552    if (unusedEntries)
1553        results.remove(0, unusedEntries);
1554
1555    return ImmutableStylePropertySet::create(results.data(), results.size(), m_context.mode);
1556}
1557
1558void CSSParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
1559{
1560    RefPtr<CSSValue> val = value.get();
1561    addProperty(propId, value, important, implicit);
1562
1563    CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId);
1564    if (prefixingVariant == propId)
1565        return;
1566    addProperty(prefixingVariant, val.release(), important, implicit);
1567}
1568
1569void CSSParser::addProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
1570{
1571    m_parsedProperties.append(CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand || implicit));
1572}
1573
1574void CSSParser::rollbackLastProperties(int num)
1575{
1576    ASSERT(num >= 0);
1577    ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
1578    m_parsedProperties.shrink(m_parsedProperties.size() - num);
1579}
1580
1581void CSSParser::clearProperties()
1582{
1583    m_parsedProperties.clear();
1584    m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
1585    m_hasFontFaceOnlyValues = false;
1586}
1587
1588KURL CSSParser::completeURL(const CSSParserContext& context, const String& url)
1589{
1590    if (url.isNull())
1591        return KURL();
1592    if (context.charset.isEmpty())
1593        return KURL(context.baseURL, url);
1594    return KURL(context.baseURL, url, context.charset);
1595}
1596
1597KURL CSSParser::completeURL(const String& url) const
1598{
1599    return completeURL(m_context, url);
1600}
1601
1602bool CSSParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc)
1603{
1604    bool mustBeNonNegative = unitflags & FNonNeg;
1605
1606    if (!parseCalculation(value, mustBeNonNegative ? CalculationRangeNonNegative : CalculationRangeAll))
1607        return false;
1608
1609    bool b = false;
1610    switch (m_parsedCalculation->category()) {
1611    case CalcLength:
1612        b = (unitflags & FLength);
1613        break;
1614    case CalcPercent:
1615        b = (unitflags & FPercent);
1616        if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1617            b = false;
1618        break;
1619    case CalcNumber:
1620        b = (unitflags & FNumber);
1621        if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
1622            b = true;
1623        if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1624            b = false;
1625        break;
1626    case CalcPercentLength:
1627        b = (unitflags & FPercent) && (unitflags & FLength);
1628        break;
1629    case CalcPercentNumber:
1630        b = (unitflags & FPercent) && (unitflags & FNumber);
1631        break;
1632#if ENABLE(CSS_VARIABLES)
1633    case CalcVariable:
1634        b = true;
1635        break;
1636#endif
1637    case CalcOther:
1638        break;
1639    }
1640    if (!b || releaseCalc == ReleaseParsedCalcValue)
1641        m_parsedCalculation.release();
1642    return b;
1643}
1644
1645inline bool CSSParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
1646{
1647    // Qirks mode and svg presentation attributes accept unit less values.
1648    return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || cssParserMode == CSSQuirksMode || cssParserMode == SVGAttributeMode);
1649}
1650
1651bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
1652{
1653    if (isCalculation(value))
1654        return validCalculationUnit(value, unitflags, releaseCalc);
1655
1656    bool b = false;
1657    switch (value->unit) {
1658#if ENABLE(CSS_VARIABLES)
1659    case CSSPrimitiveValue::CSS_VARIABLE_NAME:
1660        // Variables are checked at the point they are dereferenced because unit type is not available here.
1661        b = true;
1662        break;
1663#endif
1664    case CSSPrimitiveValue::CSS_NUMBER:
1665        b = (unitflags & FNumber);
1666        if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
1667            value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
1668                          ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
1669            b = true;
1670        }
1671        if (!b && (unitflags & FInteger) && value->isInt)
1672            b = true;
1673        if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0)
1674            b = true;
1675        break;
1676    case CSSPrimitiveValue::CSS_PERCENTAGE:
1677        b = (unitflags & FPercent);
1678        break;
1679    case CSSParserValue::Q_EMS:
1680    case CSSPrimitiveValue::CSS_EMS:
1681    case CSSPrimitiveValue::CSS_REMS:
1682    case CSSPrimitiveValue::CSS_CHS:
1683    case CSSPrimitiveValue::CSS_EXS:
1684    case CSSPrimitiveValue::CSS_PX:
1685    case CSSPrimitiveValue::CSS_CM:
1686    case CSSPrimitiveValue::CSS_MM:
1687    case CSSPrimitiveValue::CSS_IN:
1688    case CSSPrimitiveValue::CSS_PT:
1689    case CSSPrimitiveValue::CSS_PC:
1690    case CSSPrimitiveValue::CSS_VW:
1691    case CSSPrimitiveValue::CSS_VH:
1692    case CSSPrimitiveValue::CSS_VMIN:
1693    case CSSPrimitiveValue::CSS_VMAX:
1694        b = (unitflags & FLength);
1695        break;
1696    case CSSPrimitiveValue::CSS_MS:
1697    case CSSPrimitiveValue::CSS_S:
1698        b = (unitflags & FTime);
1699        break;
1700    case CSSPrimitiveValue::CSS_DEG:
1701    case CSSPrimitiveValue::CSS_RAD:
1702    case CSSPrimitiveValue::CSS_GRAD:
1703    case CSSPrimitiveValue::CSS_TURN:
1704        b = (unitflags & FAngle);
1705        break;
1706#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
1707    case CSSPrimitiveValue::CSS_DPPX:
1708    case CSSPrimitiveValue::CSS_DPI:
1709    case CSSPrimitiveValue::CSS_DPCM:
1710        b = (unitflags & FResolution);
1711        break;
1712#endif
1713    case CSSPrimitiveValue::CSS_HZ:
1714    case CSSPrimitiveValue::CSS_KHZ:
1715    case CSSPrimitiveValue::CSS_DIMENSION:
1716    default:
1717        break;
1718    }
1719    if (b && unitflags & FNonNeg && value->fValue < 0)
1720        b = false;
1721    return b;
1722}
1723
1724inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveNumericValue(CSSParserValue* value)
1725{
1726#if ENABLE(CSS_VARIABLES)
1727    if (value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
1728        return createPrimitiveVariableNameValue(value);
1729#endif
1730
1731    if (m_parsedCalculation) {
1732        ASSERT(isCalculation(value));
1733        return CSSPrimitiveValue::create(m_parsedCalculation.release());
1734    }
1735
1736#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
1737    ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1738        || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
1739        || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
1740        || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
1741#else
1742    ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1743        || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
1744        || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX));
1745#endif
1746    return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
1747}
1748
1749inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveStringValue(CSSParserValue* value)
1750{
1751    ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
1752    return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
1753}
1754
1755#if ENABLE(CSS_VARIABLES)
1756inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveVariableNameValue(CSSParserValue* value)
1757{
1758    ASSERT(value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME);
1759    return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_VARIABLE_NAME);
1760}
1761#endif
1762
1763static inline bool isComma(CSSParserValue* value)
1764{
1765    return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
1766}
1767
1768static inline bool isForwardSlashOperator(CSSParserValue* value)
1769{
1770    ASSERT(value);
1771    return value->unit == CSSParserValue::Operator && value->iValue == '/';
1772}
1773
1774bool CSSParser::validWidth(CSSParserValue* value)
1775{
1776    int id = value->id;
1777    if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
1778        return true;
1779    return !id && validUnit(value, FLength | FPercent | FNonNeg);
1780}
1781
1782// FIXME: Combine this with validWidth when we support fit-content, et al, for heights.
1783bool CSSParser::validHeight(CSSParserValue* value)
1784{
1785    int id = value->id;
1786    if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
1787        return true;
1788    return !id && validUnit(value, FLength | FPercent | FNonNeg);
1789}
1790
1791inline PassRefPtr<CSSPrimitiveValue> CSSParser::parseValidPrimitive(int identifier, CSSParserValue* value)
1792{
1793    if (identifier)
1794        return cssValuePool().createIdentifierValue(identifier);
1795    if (value->unit == CSSPrimitiveValue::CSS_STRING)
1796        return createPrimitiveStringValue(value);
1797    if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1798        return createPrimitiveNumericValue(value);
1799    if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
1800        return createPrimitiveNumericValue(value);
1801    if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
1802        return createPrimitiveNumericValue(value);
1803#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
1804    if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
1805        return createPrimitiveNumericValue(value);
1806#endif
1807#if ENABLE(CSS_VARIABLES)
1808    if (value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
1809        return createPrimitiveVariableNameValue(value);
1810#endif
1811    if (value->unit >= CSSParserValue::Q_EMS)
1812        return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
1813    if (isCalculation(value))
1814        return CSSPrimitiveValue::create(m_parsedCalculation.release());
1815
1816    return 0;
1817}
1818
1819void CSSParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtr<CSSValue> prpValue, bool important)
1820{
1821    const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
1822    unsigned shorthandLength = shorthand.length();
1823    if (!shorthandLength) {
1824        addProperty(propId, prpValue, important);
1825        return;
1826    }
1827
1828    RefPtr<CSSValue> value = prpValue;
1829    ShorthandScope scope(this, propId);
1830    const CSSPropertyID* longhands = shorthand.properties();
1831    for (unsigned i = 0; i < shorthandLength; ++i)
1832        addProperty(longhands[i], value, important);
1833}
1834
1835bool CSSParser::parseValue(CSSPropertyID propId, bool important)
1836{
1837    if (!m_valueList)
1838        return false;
1839
1840    CSSParserValue* value = m_valueList->current();
1841
1842    if (!value)
1843        return false;
1844
1845    // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
1846    // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
1847    ASSERT(!m_parsedCalculation);
1848
1849    int id = value->id;
1850
1851    int num = inShorthand() ? 1 : m_valueList->size();
1852
1853    if (id == CSSValueInherit) {
1854        if (num != 1)
1855            return false;
1856        addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important);
1857        return true;
1858    }
1859    else if (id == CSSValueInitial) {
1860        if (num != 1)
1861            return false;
1862        addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important);
1863        return true;
1864    }
1865
1866#if ENABLE(CSS_VARIABLES)
1867    if (!id && value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME && num == 1) {
1868        addProperty(propId, createPrimitiveVariableNameValue(value), important);
1869        m_valueList->next();
1870        return true;
1871    }
1872    ASSERT(propId != CSSPropertyVariable);
1873#endif
1874
1875    if (isKeywordPropertyID(propId)) {
1876        if (!isValidKeywordPropertyAndValue(propId, id, m_context))
1877            return false;
1878        if (m_valueList->next() && !inShorthand())
1879            return false;
1880        addProperty(propId, cssValuePool().createIdentifierValue(id), important);
1881        return true;
1882    }
1883
1884#if ENABLE(CSS_DEVICE_ADAPTATION)
1885    if (inViewport())
1886        return parseViewportProperty(propId, important);
1887#endif
1888
1889    bool validPrimitive = false;
1890    RefPtr<CSSValue> parsedValue;
1891
1892    switch (propId) {
1893    case CSSPropertySize:                 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
1894        return parseSize(propId, important);
1895
1896    case CSSPropertyQuotes:               // [<string> <string>]+ | none | inherit
1897        if (id)
1898            validPrimitive = true;
1899        else
1900            return parseQuotes(propId, important);
1901        break;
1902    case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | isolate-override | plaintext | inherit
1903        if (id == CSSValueNormal
1904            || id == CSSValueEmbed
1905            || id == CSSValueBidiOverride
1906            || id == CSSValueWebkitIsolate
1907            || id == CSSValueWebkitIsolateOverride
1908            || id == CSSValueWebkitPlaintext)
1909            validPrimitive = true;
1910        break;
1911
1912    case CSSPropertyContent:              // [ <string> | <uri> | <counter> | attr(X) | open-quote |
1913        // close-quote | no-open-quote | no-close-quote ]+ | inherit
1914        return parseContent(propId, important);
1915
1916    case CSSPropertyClip:                 // <shape> | auto | inherit
1917        if (id == CSSValueAuto)
1918            validPrimitive = true;
1919        else if (value->unit == CSSParserValue::Function)
1920            return parseClipShape(propId, important);
1921        break;
1922
1923    /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
1924     * correctly and allows optimization in WebCore::applyRule(..)
1925     */
1926    case CSSPropertyOverflow: {
1927        ShorthandScope scope(this, propId);
1928        if (num != 1 || !parseValue(CSSPropertyOverflowY, important))
1929            return false;
1930
1931        RefPtr<CSSValue> overflowXValue;
1932
1933        // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been
1934        // set using the shorthand, then for now overflow-x will default to auto, but once we implement
1935        // pagination controls, it should default to hidden. If the overflow-y value is anything but
1936        // paged-x or paged-y, then overflow-x and overflow-y should have the same value.
1937        if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
1938            overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
1939        else
1940            overflowXValue = m_parsedProperties.last().value();
1941        addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
1942        return true;
1943    }
1944
1945    case CSSPropertyTextAlign:
1946        // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
1947        // | start | end | inherit | -webkit-auto (converted to start)
1948        // NOTE: <string> is not supported.
1949        if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd)
1950            validPrimitive = true;
1951        break;
1952
1953    case CSSPropertyFontWeight:  { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
1954        if (m_valueList->size() != 1)
1955            return false;
1956        return parseFontWeight(important);
1957    }
1958    case CSSPropertyBorderSpacing: {
1959        if (num == 1) {
1960            ShorthandScope scope(this, CSSPropertyBorderSpacing);
1961            if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
1962                return false;
1963            CSSValue* value = m_parsedProperties.last().value();
1964            addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
1965            return true;
1966        }
1967        else if (num == 2) {
1968            ShorthandScope scope(this, CSSPropertyBorderSpacing);
1969            if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
1970                return false;
1971            return true;
1972        }
1973        return false;
1974    }
1975    case CSSPropertyWebkitBorderHorizontalSpacing:
1976    case CSSPropertyWebkitBorderVerticalSpacing:
1977        validPrimitive = validUnit(value, FLength | FNonNeg);
1978        break;
1979    case CSSPropertyOutlineColor:        // <color> | invert | inherit
1980        // Outline color has "invert" as additional keyword.
1981        // Also, we want to allow the special focus color even in strict parsing mode.
1982        if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
1983            validPrimitive = true;
1984            break;
1985        }
1986        /* nobreak */
1987    case CSSPropertyBackgroundColor: // <color> | inherit
1988    case CSSPropertyBorderTopColor: // <color> | inherit
1989    case CSSPropertyBorderRightColor:
1990    case CSSPropertyBorderBottomColor:
1991    case CSSPropertyBorderLeftColor:
1992    case CSSPropertyWebkitBorderStartColor:
1993    case CSSPropertyWebkitBorderEndColor:
1994    case CSSPropertyWebkitBorderBeforeColor:
1995    case CSSPropertyWebkitBorderAfterColor:
1996    case CSSPropertyColor: // <color> | inherit
1997    case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors
1998    case CSSPropertyTextUnderlineColor:
1999    case CSSPropertyTextOverlineColor:
2000    case CSSPropertyWebkitColumnRuleColor:
2001#if ENABLE(CSS3_TEXT)
2002    case CSSPropertyWebkitTextDecorationColor:
2003#endif // CSS3_TEXT
2004    case CSSPropertyWebkitTextEmphasisColor:
2005    case CSSPropertyWebkitTextFillColor:
2006    case CSSPropertyWebkitTextStrokeColor:
2007        if (id == CSSValueWebkitText)
2008            validPrimitive = true; // Always allow this, even when strict parsing is on,
2009                                    // since we use this in our UA sheets.
2010        else if (id == CSSValueCurrentcolor)
2011            validPrimitive = true;
2012        else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu ||
2013             (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
2014            validPrimitive = true;
2015        } else {
2016            parsedValue = parseColor();
2017            if (parsedValue)
2018                m_valueList->next();
2019        }
2020        break;
2021
2022    case CSSPropertyCursor: {
2023        // Grammar defined by CSS3 UI and modified by CSS4 images:
2024        // [ [<image> [<x> <y>]?,]*
2025        // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
2026        // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
2027        // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
2028        // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
2029        // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
2030        RefPtr<CSSValueList> list;
2031        while (value) {
2032            RefPtr<CSSValue> image = 0;
2033            if (value->unit == CSSPrimitiveValue::CSS_URI) {
2034                String uri = value->string;
2035                if (!uri.isNull())
2036                    image = CSSImageValue::create(completeURL(uri));
2037#if ENABLE(CSS_IMAGE_SET) && ENABLE(MOUSE_CURSOR_SCALE)
2038            } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
2039                image = parseImageSet();
2040                if (!image)
2041                    break;
2042#endif
2043            } else
2044                break;
2045
2046            Vector<int> coords;
2047            value = m_valueList->next();
2048            while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
2049                coords.append(int(value->fValue));
2050                value = m_valueList->next();
2051            }
2052            bool hasHotSpot = false;
2053            IntPoint hotSpot(-1, -1);
2054            int nrcoords = coords.size();
2055            if (nrcoords > 0 && nrcoords != 2)
2056                return false;
2057            if (nrcoords == 2) {
2058                hasHotSpot = true;
2059                hotSpot = IntPoint(coords[0], coords[1]);
2060            }
2061
2062            if (!list)
2063                list = CSSValueList::createCommaSeparated();
2064
2065            if (image)
2066                list->append(CSSCursorImageValue::create(image, hasHotSpot, hotSpot));
2067
2068            if ((inStrictMode() && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ',')))
2069                return false;
2070            value = m_valueList->next(); // comma
2071        }
2072        if (list) {
2073            if (!value) { // no value after url list (MSIE 5 compatibility)
2074                if (list->length() != 1)
2075                    return false;
2076            } else if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
2077                list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
2078            else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
2079                list->append(cssValuePool().createIdentifierValue(value->id));
2080            m_valueList->next();
2081            parsedValue = list.release();
2082            break;
2083        } else if (value) {
2084            id = value->id;
2085            if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
2086                id = CSSValuePointer;
2087                validPrimitive = true;
2088            } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
2089                validPrimitive = true;
2090        } else {
2091            ASSERT_NOT_REACHED();
2092            return false;
2093        }
2094        break;
2095    }
2096
2097#if ENABLE(CURSOR_VISIBILITY)
2098    case CSSPropertyWebkitCursorVisibility:
2099        if (id == CSSValueAuto || id == CSSValueAutoHide)
2100            validPrimitive = true;
2101        break;
2102#endif
2103
2104    case CSSPropertyBackgroundAttachment:
2105    case CSSPropertyBackgroundClip:
2106    case CSSPropertyWebkitBackgroundClip:
2107    case CSSPropertyWebkitBackgroundComposite:
2108    case CSSPropertyBackgroundImage:
2109    case CSSPropertyBackgroundOrigin:
2110    case CSSPropertyWebkitBackgroundOrigin:
2111    case CSSPropertyBackgroundPosition:
2112    case CSSPropertyBackgroundPositionX:
2113    case CSSPropertyBackgroundPositionY:
2114    case CSSPropertyBackgroundSize:
2115    case CSSPropertyWebkitBackgroundSize:
2116    case CSSPropertyBackgroundRepeat:
2117    case CSSPropertyBackgroundRepeatX:
2118    case CSSPropertyBackgroundRepeatY:
2119    case CSSPropertyWebkitMaskClip:
2120    case CSSPropertyWebkitMaskComposite:
2121    case CSSPropertyWebkitMaskImage:
2122    case CSSPropertyWebkitMaskOrigin:
2123    case CSSPropertyWebkitMaskPosition:
2124    case CSSPropertyWebkitMaskPositionX:
2125    case CSSPropertyWebkitMaskPositionY:
2126    case CSSPropertyWebkitMaskSize:
2127    case CSSPropertyWebkitMaskRepeat:
2128    case CSSPropertyWebkitMaskRepeatX:
2129    case CSSPropertyWebkitMaskRepeatY:
2130#if ENABLE(CSS_COMPOSITING)
2131    case CSSPropertyWebkitBackgroundBlendMode:
2132#endif
2133    {
2134        RefPtr<CSSValue> val1;
2135        RefPtr<CSSValue> val2;
2136        CSSPropertyID propId1, propId2;
2137        bool result = false;
2138        if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
2139            OwnPtr<ShorthandScope> shorthandScope;
2140            if (propId == CSSPropertyBackgroundPosition ||
2141                propId == CSSPropertyBackgroundRepeat ||
2142                propId == CSSPropertyWebkitMaskPosition ||
2143                propId == CSSPropertyWebkitMaskRepeat) {
2144                shorthandScope = adoptPtr(new ShorthandScope(this, propId));
2145            }
2146            addProperty(propId1, val1.release(), important);
2147            if (val2)
2148                addProperty(propId2, val2.release(), important);
2149            result = true;
2150        }
2151        m_implicitShorthand = false;
2152        return result;
2153    }
2154    case CSSPropertyListStyleImage:     // <uri> | none | inherit
2155    case CSSPropertyBorderImageSource:
2156    case CSSPropertyWebkitMaskBoxImageSource:
2157        if (id == CSSValueNone) {
2158            parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
2159            m_valueList->next();
2160        } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
2161            parsedValue = CSSImageValue::create(completeURL(value->string));
2162            m_valueList->next();
2163        } else if (isGeneratedImageValue(value)) {
2164            if (parseGeneratedImage(m_valueList.get(), parsedValue))
2165                m_valueList->next();
2166            else
2167                return false;
2168        }
2169#if ENABLE(CSS_IMAGE_SET)
2170        else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
2171            parsedValue = parseImageSet();
2172            if (!parsedValue)
2173                return false;
2174            m_valueList->next();
2175        }
2176#endif
2177        break;
2178
2179    case CSSPropertyWebkitTextStrokeWidth:
2180    case CSSPropertyOutlineWidth:        // <border-width> | inherit
2181    case CSSPropertyBorderTopWidth:     //// <border-width> | inherit
2182    case CSSPropertyBorderRightWidth:   //   Which is defined as
2183    case CSSPropertyBorderBottomWidth:  //   thin | medium | thick | <length>
2184    case CSSPropertyBorderLeftWidth:
2185    case CSSPropertyWebkitBorderStartWidth:
2186    case CSSPropertyWebkitBorderEndWidth:
2187    case CSSPropertyWebkitBorderBeforeWidth:
2188    case CSSPropertyWebkitBorderAfterWidth:
2189    case CSSPropertyWebkitColumnRuleWidth:
2190        if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
2191            validPrimitive = true;
2192        else
2193            validPrimitive = validUnit(value, FLength | FNonNeg);
2194        break;
2195
2196    case CSSPropertyLetterSpacing:       // normal | <length> | inherit
2197    case CSSPropertyWordSpacing:         // normal | <length> | inherit
2198        if (id == CSSValueNormal)
2199            validPrimitive = true;
2200        else
2201            validPrimitive = validUnit(value, FLength);
2202        break;
2203
2204    case CSSPropertyTextIndent:
2205        parsedValue = parseTextIndent();
2206        break;
2207
2208    case CSSPropertyPaddingTop:          //// <padding-width> | inherit
2209    case CSSPropertyPaddingRight:        //   Which is defined as
2210    case CSSPropertyPaddingBottom:       //   <length> | <percentage>
2211    case CSSPropertyPaddingLeft:         ////
2212    case CSSPropertyWebkitPaddingStart:
2213    case CSSPropertyWebkitPaddingEnd:
2214    case CSSPropertyWebkitPaddingBefore:
2215    case CSSPropertyWebkitPaddingAfter:
2216        validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
2217        break;
2218
2219    case CSSPropertyMaxWidth:
2220    case CSSPropertyWebkitMaxLogicalWidth:
2221        validPrimitive = (id == CSSValueNone || validWidth(value));
2222        break;
2223
2224    case CSSPropertyMinWidth:
2225    case CSSPropertyWebkitMinLogicalWidth:
2226        validPrimitive = validWidth(value);
2227        break;
2228
2229    case CSSPropertyWidth:
2230    case CSSPropertyWebkitLogicalWidth:
2231        validPrimitive = (id == CSSValueAuto || validWidth(value));
2232        break;
2233
2234    case CSSPropertyMaxHeight:
2235    case CSSPropertyWebkitMaxLogicalHeight:
2236        validPrimitive = (id == CSSValueNone || validHeight(value));
2237        break;
2238
2239    case CSSPropertyMinHeight:
2240    case CSSPropertyWebkitMinLogicalHeight:
2241        validPrimitive = validHeight(value);
2242        break;
2243
2244    case CSSPropertyHeight:
2245    case CSSPropertyWebkitLogicalHeight:
2246        validPrimitive = (id == CSSValueAuto || validHeight(value));
2247        break;
2248
2249    case CSSPropertyFontSize:
2250        return parseFontSize(important);
2251
2252    case CSSPropertyFontVariant:         // normal | small-caps | inherit
2253        return parseFontVariant(important);
2254
2255    case CSSPropertyVerticalAlign:
2256        // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
2257        // <percentage> | <length> | inherit
2258
2259        if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
2260            validPrimitive = true;
2261        else
2262            validPrimitive = (!id && validUnit(value, FLength | FPercent));
2263        break;
2264
2265    case CSSPropertyBottom:               // <length> | <percentage> | auto | inherit
2266    case CSSPropertyLeft:                 // <length> | <percentage> | auto | inherit
2267    case CSSPropertyRight:                // <length> | <percentage> | auto | inherit
2268    case CSSPropertyTop:                  // <length> | <percentage> | auto | inherit
2269    case CSSPropertyMarginTop:           //// <margin-width> | inherit
2270    case CSSPropertyMarginRight:         //   Which is defined as
2271    case CSSPropertyMarginBottom:        //   <length> | <percentage> | auto | inherit
2272    case CSSPropertyMarginLeft:          ////
2273    case CSSPropertyWebkitMarginStart:
2274    case CSSPropertyWebkitMarginEnd:
2275    case CSSPropertyWebkitMarginBefore:
2276    case CSSPropertyWebkitMarginAfter:
2277        if (id == CSSValueAuto)
2278            validPrimitive = true;
2279        else
2280            validPrimitive = (!id && validUnit(value, FLength | FPercent));
2281        break;
2282
2283    case CSSPropertyZIndex:              // auto | <integer> | inherit
2284        if (id == CSSValueAuto) {
2285            validPrimitive = true;
2286            break;
2287        }
2288        /* nobreak */
2289    case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
2290    case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
2291        if (id == CSSValueAuto)
2292            validPrimitive = true;
2293        else
2294            validPrimitive = (!id && validUnit(value, FInteger, CSSQuirksMode));
2295        break;
2296
2297    case CSSPropertyLineHeight:
2298        return parseLineHeight(important);
2299    case CSSPropertyCounterIncrement:    // [ <identifier> <integer>? ]+ | none | inherit
2300        if (id != CSSValueNone)
2301            return parseCounter(propId, 1, important);
2302        validPrimitive = true;
2303        break;
2304    case CSSPropertyCounterReset:        // [ <identifier> <integer>? ]+ | none | inherit
2305        if (id != CSSValueNone)
2306            return parseCounter(propId, 0, important);
2307        validPrimitive = true;
2308        break;
2309    case CSSPropertyFontFamily:
2310        // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
2311    {
2312        parsedValue = parseFontFamily();
2313        break;
2314    }
2315
2316    case CSSPropertyTextDecoration:
2317    case CSSPropertyWebkitTextDecorationsInEffect:
2318#if ENABLE(CSS3_TEXT)
2319    case CSSPropertyWebkitTextDecorationLine:
2320#endif // CSS3_TEXT
2321        // none | [ underline || overline || line-through || blink ] | inherit
2322        return parseTextDecoration(propId, important);
2323
2324#if ENABLE(CSS3_TEXT)
2325    case CSSPropertyWebkitTextDecorationStyle:
2326        // solid | double | dotted | dashed | wavy
2327        if (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDotted || id == CSSValueDashed || id == CSSValueWavy)
2328            validPrimitive = true;
2329        break;
2330
2331    case CSSPropertyWebkitTextUnderlinePosition:
2332        // auto | alphabetic | under
2333        return parseTextUnderlinePosition(important);
2334#endif // CSS3_TEXT
2335
2336    case CSSPropertyZoom:          // normal | reset | document | <number> | <percentage> | inherit
2337        if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
2338            validPrimitive = true;
2339        else
2340            validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode));
2341        break;
2342
2343    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.
2344#if ENABLE(CSS_SHADERS)
2345        if (m_inFilterRule)
2346            return parseFilterRuleSrc();
2347#endif
2348        return parseFontFaceSrc();
2349
2350#if ENABLE(CSS_SHADERS)
2351    case CSSPropertyMix:
2352        // The mix property is just supported inside of an @filter rule.
2353        if (!m_inFilterRule)
2354            return false;
2355        return parseFilterRuleMix();
2356    case CSSPropertyParameters:
2357        // The parameters property is just supported inside of an @filter rule.
2358        if (!m_inFilterRule)
2359            return false;
2360        return parseFilterRuleParameters();
2361#endif
2362
2363    case CSSPropertyUnicodeRange:
2364        return parseFontFaceUnicodeRange();
2365
2366    /* CSS3 properties */
2367
2368    case CSSPropertyBorderImage: {
2369        RefPtr<CSSValue> result;
2370        return parseBorderImage(propId, result, important);
2371    }
2372    case CSSPropertyWebkitBorderImage:
2373    case CSSPropertyWebkitMaskBoxImage: {
2374        RefPtr<CSSValue> result;
2375        if (parseBorderImage(propId, result)) {
2376            addProperty(propId, result, important);
2377            return true;
2378        }
2379        break;
2380    }
2381    case CSSPropertyBorderImageOutset:
2382    case CSSPropertyWebkitMaskBoxImageOutset: {
2383        RefPtr<CSSPrimitiveValue> result;
2384        if (parseBorderImageOutset(result)) {
2385            addProperty(propId, result, important);
2386            return true;
2387        }
2388        break;
2389    }
2390    case CSSPropertyBorderImageRepeat:
2391    case CSSPropertyWebkitMaskBoxImageRepeat: {
2392        RefPtr<CSSValue> result;
2393        if (parseBorderImageRepeat(result)) {
2394            addProperty(propId, result, important);
2395            return true;
2396        }
2397        break;
2398    }
2399    case CSSPropertyBorderImageSlice:
2400    case CSSPropertyWebkitMaskBoxImageSlice: {
2401        RefPtr<CSSBorderImageSliceValue> result;
2402        if (parseBorderImageSlice(propId, result)) {
2403            addProperty(propId, result, important);
2404            return true;
2405        }
2406        break;
2407    }
2408    case CSSPropertyBorderImageWidth:
2409    case CSSPropertyWebkitMaskBoxImageWidth: {
2410        RefPtr<CSSPrimitiveValue> result;
2411        if (parseBorderImageWidth(result)) {
2412            addProperty(propId, result, important);
2413            return true;
2414        }
2415        break;
2416    }
2417    case CSSPropertyBorderTopRightRadius:
2418    case CSSPropertyBorderTopLeftRadius:
2419    case CSSPropertyBorderBottomLeftRadius:
2420    case CSSPropertyBorderBottomRightRadius: {
2421        if (num != 1 && num != 2)
2422            return false;
2423        validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2424        if (!validPrimitive)
2425            return false;
2426        RefPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
2427        RefPtr<CSSPrimitiveValue> parsedValue2;
2428        if (num == 2) {
2429            value = m_valueList->next();
2430            validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2431            if (!validPrimitive)
2432                return false;
2433            parsedValue2 = createPrimitiveNumericValue(value);
2434        } else
2435            parsedValue2 = parsedValue1;
2436
2437        addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important);
2438        return true;
2439    }
2440    case CSSPropertyTabSize:
2441        validPrimitive = validUnit(value, FInteger | FNonNeg);
2442        break;
2443    case CSSPropertyWebkitAspectRatio:
2444        return parseAspectRatio(important);
2445    case CSSPropertyBorderRadius:
2446    case CSSPropertyWebkitBorderRadius:
2447        return parseBorderRadius(propId, important);
2448    case CSSPropertyOutlineOffset:
2449        validPrimitive = validUnit(value, FLength | FPercent);
2450        break;
2451    case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
2452    case CSSPropertyBoxShadow:
2453    case CSSPropertyWebkitBoxShadow:
2454        if (id == CSSValueNone)
2455            validPrimitive = true;
2456        else {
2457            RefPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
2458            if (shadowValueList) {
2459                addProperty(propId, shadowValueList.release(), important);
2460                m_valueList->next();
2461                return true;
2462            }
2463            return false;
2464        }
2465        break;
2466    case CSSPropertyWebkitBoxReflect:
2467        if (id == CSSValueNone)
2468            validPrimitive = true;
2469        else
2470            return parseReflect(propId, important);
2471        break;
2472    case CSSPropertyOpacity:
2473        validPrimitive = validUnit(value, FNumber);
2474        break;
2475    case CSSPropertyWebkitBoxFlex:
2476        validPrimitive = validUnit(value, FNumber);
2477        break;
2478    case CSSPropertyWebkitBoxFlexGroup:
2479        validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode);
2480        break;
2481    case CSSPropertyWebkitBoxOrdinalGroup:
2482        validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode) && value->fValue;
2483        break;
2484#if ENABLE(CSS_FILTERS)
2485    case CSSPropertyWebkitFilter:
2486        if (id == CSSValueNone)
2487            validPrimitive = true;
2488        else {
2489            RefPtr<CSSValue> val = parseFilter();
2490            if (val) {
2491                addProperty(propId, val, important);
2492                return true;
2493            }
2494            return false;
2495        }
2496        break;
2497#endif
2498#if ENABLE(CSS_COMPOSITING)
2499    case CSSPropertyWebkitBlendMode:
2500        if (cssCompositingEnabled())
2501            validPrimitive = true;
2502        break;
2503#endif
2504    case CSSPropertyWebkitFlex: {
2505        ShorthandScope scope(this, propId);
2506        if (id == CSSValueNone) {
2507            addProperty(CSSPropertyWebkitFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
2508            addProperty(CSSPropertyWebkitFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
2509            addProperty(CSSPropertyWebkitFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
2510            return true;
2511        }
2512        return parseFlex(m_valueList.get(), important);
2513    }
2514    case CSSPropertyWebkitFlexBasis:
2515        // FIXME: Support intrinsic dimensions too.
2516        if (id == CSSValueAuto)
2517            validPrimitive = true;
2518        else
2519            validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
2520        break;
2521    case CSSPropertyWebkitFlexGrow:
2522    case CSSPropertyWebkitFlexShrink:
2523        validPrimitive = validUnit(value, FNumber | FNonNeg);
2524        break;
2525    case CSSPropertyWebkitOrder:
2526        if (validUnit(value, FInteger, CSSStrictMode)) {
2527            // 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.
2528            parsedValue = cssValuePool().createValue(max(static_cast<double>(std::numeric_limits<int>::min() + 2), value->fValue),
2529                                                             static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
2530            m_valueList->next();
2531        }
2532        break;
2533    case CSSPropertyWebkitMarquee:
2534        return parseShorthand(propId, webkitMarqueeShorthand(), important);
2535    case CSSPropertyWebkitMarqueeIncrement:
2536        if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
2537            validPrimitive = true;
2538        else
2539            validPrimitive = validUnit(value, FLength | FPercent);
2540        break;
2541    case CSSPropertyWebkitMarqueeRepetition:
2542        if (id == CSSValueInfinite)
2543            validPrimitive = true;
2544        else
2545            validPrimitive = validUnit(value, FInteger | FNonNeg);
2546        break;
2547    case CSSPropertyWebkitMarqueeSpeed:
2548        if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
2549            validPrimitive = true;
2550        else
2551            validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
2552        break;
2553#if ENABLE(CSS_REGIONS)
2554    case CSSPropertyWebkitFlowInto:
2555        if (!cssRegionsEnabled())
2556            return false;
2557        return parseFlowThread(propId, important);
2558    case CSSPropertyWebkitFlowFrom:
2559        if (!cssRegionsEnabled())
2560            return false;
2561        return parseRegionThread(propId, important);
2562#endif
2563    case CSSPropertyWebkitTransform:
2564        if (id == CSSValueNone)
2565            validPrimitive = true;
2566        else {
2567            RefPtr<CSSValue> transformValue = parseTransform();
2568            if (transformValue) {
2569                addProperty(propId, transformValue.release(), important);
2570                return true;
2571            }
2572            return false;
2573        }
2574        break;
2575    case CSSPropertyWebkitTransformOrigin:
2576    case CSSPropertyWebkitTransformOriginX:
2577    case CSSPropertyWebkitTransformOriginY:
2578    case CSSPropertyWebkitTransformOriginZ: {
2579        RefPtr<CSSValue> val1;
2580        RefPtr<CSSValue> val2;
2581        RefPtr<CSSValue> val3;
2582        CSSPropertyID propId1, propId2, propId3;
2583        if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
2584            addProperty(propId1, val1.release(), important);
2585            if (val2)
2586                addProperty(propId2, val2.release(), important);
2587            if (val3)
2588                addProperty(propId3, val3.release(), important);
2589            return true;
2590        }
2591        return false;
2592    }
2593    case CSSPropertyWebkitPerspective:
2594        if (id == CSSValueNone)
2595            validPrimitive = true;
2596        else {
2597            // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
2598            if (validUnit(value, FNumber | FLength | FNonNeg)) {
2599                RefPtr<CSSValue> val = createPrimitiveNumericValue(value);
2600                if (val) {
2601                    addProperty(propId, val.release(), important);
2602                    return true;
2603                }
2604                return false;
2605            }
2606        }
2607        break;
2608    case CSSPropertyWebkitPerspectiveOrigin:
2609    case CSSPropertyWebkitPerspectiveOriginX:
2610    case CSSPropertyWebkitPerspectiveOriginY: {
2611        RefPtr<CSSValue> val1;
2612        RefPtr<CSSValue> val2;
2613        CSSPropertyID propId1, propId2;
2614        if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
2615            addProperty(propId1, val1.release(), important);
2616            if (val2)
2617                addProperty(propId2, val2.release(), important);
2618            return true;
2619        }
2620        return false;
2621    }
2622    case CSSPropertyWebkitAnimationDelay:
2623    case CSSPropertyWebkitAnimationDirection:
2624    case CSSPropertyWebkitAnimationDuration:
2625    case CSSPropertyWebkitAnimationFillMode:
2626    case CSSPropertyWebkitAnimationName:
2627    case CSSPropertyWebkitAnimationPlayState:
2628    case CSSPropertyWebkitAnimationIterationCount:
2629    case CSSPropertyWebkitAnimationTimingFunction:
2630    case CSSPropertyTransitionDelay:
2631    case CSSPropertyTransitionDuration:
2632    case CSSPropertyTransitionTimingFunction:
2633    case CSSPropertyTransitionProperty:
2634    case CSSPropertyWebkitTransitionDelay:
2635    case CSSPropertyWebkitTransitionDuration:
2636    case CSSPropertyWebkitTransitionTimingFunction:
2637    case CSSPropertyWebkitTransitionProperty: {
2638        RefPtr<CSSValue> val;
2639        AnimationParseContext context;
2640        if (parseAnimationProperty(propId, val, context)) {
2641            addPropertyWithPrefixingVariant(propId, val.release(), important);
2642            return true;
2643        }
2644        return false;
2645    }
2646
2647    case CSSPropertyWebkitGridAutoColumns:
2648    case CSSPropertyWebkitGridAutoRows:
2649        if (!cssGridLayoutEnabled())
2650            return false;
2651        parsedValue = parseGridTrackSize();
2652        break;
2653
2654    case CSSPropertyWebkitGridColumns:
2655    case CSSPropertyWebkitGridRows:
2656        if (!cssGridLayoutEnabled())
2657            return false;
2658        return parseGridTrackList(propId, important);
2659
2660    case CSSPropertyWebkitGridStart:
2661    case CSSPropertyWebkitGridEnd:
2662    case CSSPropertyWebkitGridBefore:
2663    case CSSPropertyWebkitGridAfter:
2664        if (!cssGridLayoutEnabled())
2665            return false;
2666
2667        validPrimitive = id == CSSValueAuto || (validUnit(value, FInteger) && value->fValue);
2668        break;
2669
2670    case CSSPropertyWebkitGridColumn:
2671    case CSSPropertyWebkitGridRow: {
2672        if (!cssGridLayoutEnabled())
2673            return false;
2674
2675        return parseGridItemPositionShorthand(propId, important);
2676    }
2677
2678    case CSSPropertyWebkitMarginCollapse: {
2679        if (num == 1) {
2680            ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2681            if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important))
2682                return false;
2683            CSSValue* value = m_parsedProperties.last().value();
2684            addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
2685            return true;
2686        }
2687        else if (num == 2) {
2688            ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2689            if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important) || !parseValue(webkitMarginCollapseShorthand().properties()[1], important))
2690                return false;
2691            return true;
2692        }
2693        return false;
2694    }
2695    case CSSPropertyTextLineThroughWidth:
2696    case CSSPropertyTextOverlineWidth:
2697    case CSSPropertyTextUnderlineWidth:
2698        if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
2699            id == CSSValueMedium || id == CSSValueThick)
2700            validPrimitive = true;
2701        else
2702            validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent);
2703        break;
2704    case CSSPropertyWebkitColumnCount:
2705        if (id == CSSValueAuto)
2706            validPrimitive = true;
2707        else
2708            validPrimitive = !id && validUnit(value, FPositiveInteger, CSSQuirksMode);
2709        break;
2710    case CSSPropertyWebkitColumnGap:         // normal | <length>
2711        if (id == CSSValueNormal)
2712            validPrimitive = true;
2713        else
2714            validPrimitive = validUnit(value, FLength | FNonNeg);
2715        break;
2716    case CSSPropertyWebkitColumnAxis:
2717        if (id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
2718            validPrimitive = true;
2719        break;
2720    case CSSPropertyWebkitColumnProgression:
2721        if (id == CSSValueNormal || id == CSSValueReverse)
2722            validPrimitive = true;
2723        break;
2724    case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property)
2725        if (id == CSSValueAll || id == CSSValueNone)
2726            validPrimitive = true;
2727        else
2728            validPrimitive = validUnit(value, FNumber | FNonNeg) && value->fValue == 1;
2729        break;
2730    case CSSPropertyWebkitColumnWidth:         // auto | <length>
2731        if (id == CSSValueAuto)
2732            validPrimitive = true;
2733        else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property.
2734            validPrimitive = validUnit(value, FLength | FNonNeg, CSSStrictMode) && value->fValue;
2735        break;
2736    // End of CSS3 properties
2737
2738    // Apple specific properties.  These will never be standardized and are purely to
2739    // support custom WebKit-based Apple applications.
2740    case CSSPropertyWebkitLineClamp:
2741        // When specifying number of lines, don't allow 0 as a valid value
2742        // When specifying either type of unit, require non-negative integers
2743        validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, CSSQuirksMode));
2744        break;
2745
2746    case CSSPropertyWebkitFontSizeDelta:           // <length>
2747        validPrimitive = validUnit(value, FLength);
2748        break;
2749
2750    case CSSPropertyWebkitHighlight:
2751        if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
2752            validPrimitive = true;
2753        break;
2754
2755    case CSSPropertyWebkitHyphenateCharacter:
2756        if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2757            validPrimitive = true;
2758        break;
2759
2760    case CSSPropertyWebkitHyphenateLimitBefore:
2761    case CSSPropertyWebkitHyphenateLimitAfter:
2762        if (id == CSSValueAuto || validUnit(value, FInteger | FNonNeg, CSSStrictMode))
2763            validPrimitive = true;
2764        break;
2765
2766    case CSSPropertyWebkitHyphenateLimitLines:
2767        if (id == CSSValueNoLimit || validUnit(value, FInteger | FNonNeg, CSSStrictMode))
2768            validPrimitive = true;
2769        break;
2770
2771    case CSSPropertyWebkitLineGrid:
2772        if (id == CSSValueNone)
2773            validPrimitive = true;
2774        else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
2775            String lineGridValue = String(value->string);
2776            if (!lineGridValue.isEmpty()) {
2777                addProperty(propId, cssValuePool().createValue(lineGridValue, CSSPrimitiveValue::CSS_STRING), important);
2778                return true;
2779            }
2780        }
2781        break;
2782    case CSSPropertyWebkitLocale:
2783        if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2784            validPrimitive = true;
2785        break;
2786
2787#if ENABLE(DASHBOARD_SUPPORT)
2788    case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region>
2789        if (value->unit == CSSParserValue::Function || id == CSSValueNone)
2790            return parseDashboardRegions(propId, important);
2791        break;
2792#endif
2793    // End Apple-specific properties
2794
2795#if ENABLE(DRAGGABLE_REGION)
2796    case CSSPropertyWebkitAppRegion:
2797        if (id >= CSSValueDrag && id <= CSSValueNoDrag)
2798            validPrimitive = true;
2799        break;
2800#endif
2801
2802#if ENABLE(TOUCH_EVENTS)
2803    case CSSPropertyWebkitTapHighlightColor:
2804        if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu
2805            || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
2806            validPrimitive = true;
2807        } else {
2808            parsedValue = parseColor();
2809            if (parsedValue)
2810                m_valueList->next();
2811        }
2812        break;
2813#endif
2814
2815        /* shorthand properties */
2816    case CSSPropertyBackground: {
2817        // Position must come before color in this array because a plain old "0" is a legal color
2818        // in quirks mode but it's usually the X coordinate of a position.
2819        const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
2820                                   CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
2821                                   CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
2822        return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
2823    }
2824    case CSSPropertyWebkitMask: {
2825        const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
2826            CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize };
2827        return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
2828    }
2829    case CSSPropertyBorder:
2830        // [ 'border-width' || 'border-style' || <color> ] | inherit
2831    {
2832        if (parseShorthand(propId, borderAbridgedShorthand(), important)) {
2833            // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as
2834            // though a value of none was specified for the image.
2835            addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
2836            return true;
2837        }
2838        return false;
2839    }
2840    case CSSPropertyBorderTop:
2841        // [ 'border-top-width' || 'border-style' || <color> ] | inherit
2842        return parseShorthand(propId, borderTopShorthand(), important);
2843    case CSSPropertyBorderRight:
2844        // [ 'border-right-width' || 'border-style' || <color> ] | inherit
2845        return parseShorthand(propId, borderRightShorthand(), important);
2846    case CSSPropertyBorderBottom:
2847        // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
2848        return parseShorthand(propId, borderBottomShorthand(), important);
2849    case CSSPropertyBorderLeft:
2850        // [ 'border-left-width' || 'border-style' || <color> ] | inherit
2851        return parseShorthand(propId, borderLeftShorthand(), important);
2852    case CSSPropertyWebkitBorderStart:
2853        return parseShorthand(propId, webkitBorderStartShorthand(), important);
2854    case CSSPropertyWebkitBorderEnd:
2855        return parseShorthand(propId, webkitBorderEndShorthand(), important);
2856    case CSSPropertyWebkitBorderBefore:
2857        return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
2858    case CSSPropertyWebkitBorderAfter:
2859        return parseShorthand(propId, webkitBorderAfterShorthand(), important);
2860    case CSSPropertyOutline:
2861        // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
2862        return parseShorthand(propId, outlineShorthand(), important);
2863    case CSSPropertyBorderColor:
2864        // <color>{1,4} | inherit
2865        return parse4Values(propId, borderColorShorthand().properties(), important);
2866    case CSSPropertyBorderWidth:
2867        // <border-width>{1,4} | inherit
2868        return parse4Values(propId, borderWidthShorthand().properties(), important);
2869    case CSSPropertyBorderStyle:
2870        // <border-style>{1,4} | inherit
2871        return parse4Values(propId, borderStyleShorthand().properties(), important);
2872    case CSSPropertyMargin:
2873        // <margin-width>{1,4} | inherit
2874        return parse4Values(propId, marginShorthand().properties(), important);
2875    case CSSPropertyPadding:
2876        // <padding-width>{1,4} | inherit
2877        return parse4Values(propId, paddingShorthand().properties(), important);
2878    case CSSPropertyWebkitFlexFlow:
2879        return parseShorthand(propId, webkitFlexFlowShorthand(), important);
2880    case CSSPropertyFont:
2881        // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
2882        // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
2883        if (id >= CSSValueCaption && id <= CSSValueStatusBar)
2884            validPrimitive = true;
2885        else
2886            return parseFont(important);
2887        break;
2888    case CSSPropertyListStyle:
2889        return parseShorthand(propId, listStyleShorthand(), important);
2890    case CSSPropertyWebkitColumns:
2891        return parseShorthand(propId, webkitColumnsShorthand(), important);
2892    case CSSPropertyWebkitColumnRule:
2893        return parseShorthand(propId, webkitColumnRuleShorthand(), important);
2894    case CSSPropertyWebkitTextStroke:
2895        return parseShorthand(propId, webkitTextStrokeShorthand(), important);
2896    case CSSPropertyWebkitAnimation:
2897        return parseAnimationShorthand(important);
2898    case CSSPropertyTransition:
2899    case CSSPropertyWebkitTransition:
2900        return parseTransitionShorthand(propId, important);
2901    case CSSPropertyInvalid:
2902        return false;
2903    case CSSPropertyPage:
2904        return parsePage(propId, important);
2905#if ENABLE(CSS_SHADERS)
2906    case CSSPropertyGeometry:
2907        return m_inFilterRule ? parseGeometry(propId, value, important) : false;
2908#endif
2909    case CSSPropertyFontStretch:
2910    case CSSPropertyTextLineThrough:
2911    case CSSPropertyTextOverline:
2912    case CSSPropertyTextUnderline:
2913        return false;
2914    // CSS Text Layout Module Level 3: Vertical writing support
2915    case CSSPropertyWebkitTextEmphasis:
2916        return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
2917
2918    case CSSPropertyWebkitTextEmphasisStyle:
2919        return parseTextEmphasisStyle(important);
2920
2921    case CSSPropertyWebkitTextOrientation:
2922        // FIXME: For now just support sideways, sideways-right, upright and vertical-right.
2923        if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSValueVerticalRight || id == CSSValueUpright)
2924            validPrimitive = true;
2925        break;
2926
2927    case CSSPropertyWebkitLineBoxContain:
2928        if (id == CSSValueNone)
2929            validPrimitive = true;
2930        else
2931            return parseLineBoxContain(important);
2932        break;
2933    case CSSPropertyWebkitFontFeatureSettings:
2934        if (id == CSSValueNormal)
2935            validPrimitive = true;
2936        else
2937            return parseFontFeatureSettings(important);
2938        break;
2939
2940    case CSSPropertyWebkitFontVariantLigatures:
2941        if (id == CSSValueNormal)
2942            validPrimitive = true;
2943        else
2944            return parseFontVariantLigatures(important);
2945        break;
2946    case CSSPropertyWebkitClipPath:
2947        if (id == CSSValueNone)
2948            validPrimitive = true;
2949        else if (value->unit == CSSParserValue::Function)
2950            return parseBasicShape(propId, important);
2951#if ENABLE(SVG)
2952        else if (value->unit == CSSPrimitiveValue::CSS_URI) {
2953            parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
2954            addProperty(propId, parsedValue.release(), important);
2955            return true;
2956        }
2957#endif
2958        break;
2959#if ENABLE(CSS_SHAPES)
2960    case CSSPropertyWebkitShapeInside:
2961    case CSSPropertyWebkitShapeOutside:
2962        if (!RuntimeEnabledFeatures::cssShapesEnabled())
2963            return false;
2964        if (id == CSSValueAuto)
2965            validPrimitive = true;
2966        else if (propId == CSSPropertyWebkitShapeInside && id == CSSValueOutsideShape)
2967            validPrimitive = true;
2968        else if (value->unit == CSSParserValue::Function)
2969            return parseBasicShape(propId, important);
2970        else if (value->unit == CSSPrimitiveValue::CSS_URI) {
2971            parsedValue = CSSImageValue::create(completeURL(value->string));
2972            m_valueList->next();
2973        }
2974        break;
2975    case CSSPropertyWebkitShapeMargin:
2976    case CSSPropertyWebkitShapePadding:
2977        validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FLength | FNonNeg));
2978        break;
2979#endif
2980#if ENABLE(CSS_IMAGE_ORIENTATION)
2981    case CSSPropertyImageOrientation:
2982        validPrimitive = !id && validUnit(value, FAngle);
2983        break;
2984#endif
2985#if ENABLE(CSS_IMAGE_RESOLUTION)
2986    case CSSPropertyImageResolution:
2987        parsedValue = parseImageResolution();
2988        break;
2989#endif
2990    case CSSPropertyBorderBottomStyle:
2991    case CSSPropertyBorderCollapse:
2992    case CSSPropertyBorderLeftStyle:
2993    case CSSPropertyBorderRightStyle:
2994    case CSSPropertyBorderTopStyle:
2995    case CSSPropertyBoxSizing:
2996    case CSSPropertyCaptionSide:
2997    case CSSPropertyClear:
2998    case CSSPropertyDirection:
2999    case CSSPropertyDisplay:
3000    case CSSPropertyEmptyCells:
3001    case CSSPropertyFloat:
3002    case CSSPropertyFontStyle:
3003    case CSSPropertyImageRendering:
3004    case CSSPropertyListStylePosition:
3005    case CSSPropertyListStyleType:
3006    case CSSPropertyOutlineStyle:
3007    case CSSPropertyOverflowWrap:
3008    case CSSPropertyOverflowX:
3009    case CSSPropertyOverflowY:
3010    case CSSPropertyPageBreakAfter:
3011    case CSSPropertyPageBreakBefore:
3012    case CSSPropertyPageBreakInside:
3013    case CSSPropertyPointerEvents:
3014    case CSSPropertyPosition:
3015    case CSSPropertyResize:
3016    case CSSPropertySpeak:
3017    case CSSPropertyTableLayout:
3018    case CSSPropertyTextLineThroughMode:
3019    case CSSPropertyTextLineThroughStyle:
3020    case CSSPropertyTextOverflow:
3021    case CSSPropertyTextOverlineMode:
3022    case CSSPropertyTextOverlineStyle:
3023    case CSSPropertyTextRendering:
3024    case CSSPropertyTextTransform:
3025    case CSSPropertyTextUnderlineMode:
3026    case CSSPropertyTextUnderlineStyle:
3027#if ENABLE(CSS_VARIABLES)
3028    case CSSPropertyVariable:
3029#endif
3030    case CSSPropertyVisibility:
3031    case CSSPropertyWebkitAppearance:
3032    case CSSPropertyWebkitBackfaceVisibility:
3033    case CSSPropertyWebkitBorderAfterStyle:
3034    case CSSPropertyWebkitBorderBeforeStyle:
3035    case CSSPropertyWebkitBorderEndStyle:
3036    case CSSPropertyWebkitBorderFit:
3037    case CSSPropertyWebkitBorderStartStyle:
3038    case CSSPropertyWebkitBoxAlign:
3039#if ENABLE(CSS_BOX_DECORATION_BREAK)
3040    case CSSPropertyWebkitBoxDecorationBreak:
3041#endif
3042    case CSSPropertyWebkitBoxDirection:
3043    case CSSPropertyWebkitBoxLines:
3044    case CSSPropertyWebkitBoxOrient:
3045    case CSSPropertyWebkitBoxPack:
3046    case CSSPropertyWebkitColorCorrection:
3047    case CSSPropertyWebkitColumnBreakAfter:
3048    case CSSPropertyWebkitColumnBreakBefore:
3049    case CSSPropertyWebkitColumnBreakInside:
3050    case CSSPropertyWebkitColumnRuleStyle:
3051    case CSSPropertyWebkitAlignContent:
3052    case CSSPropertyWebkitAlignItems:
3053    case CSSPropertyWebkitAlignSelf:
3054    case CSSPropertyWebkitFlexDirection:
3055    case CSSPropertyWebkitFlexWrap:
3056    case CSSPropertyWebkitJustifyContent:
3057    case CSSPropertyWebkitFontKerning:
3058    case CSSPropertyWebkitFontSmoothing:
3059    case CSSPropertyWebkitHyphens:
3060    case CSSPropertyWebkitGridAutoFlow:
3061    case CSSPropertyWebkitLineAlign:
3062    case CSSPropertyWebkitLineBreak:
3063    case CSSPropertyWebkitLineSnap:
3064    case CSSPropertyWebkitMarginAfterCollapse:
3065    case CSSPropertyWebkitMarginBeforeCollapse:
3066    case CSSPropertyWebkitMarginBottomCollapse:
3067    case CSSPropertyWebkitMarginTopCollapse:
3068    case CSSPropertyWebkitMarqueeDirection:
3069    case CSSPropertyWebkitMarqueeStyle:
3070    case CSSPropertyWebkitNbspMode:
3071#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
3072    case CSSPropertyWebkitOverflowScrolling:
3073#endif
3074    case CSSPropertyWebkitPrintColorAdjust:
3075#if ENABLE(CSS_REGIONS)
3076    case CSSPropertyWebkitRegionBreakAfter:
3077    case CSSPropertyWebkitRegionBreakBefore:
3078    case CSSPropertyWebkitRegionBreakInside:
3079    case CSSPropertyWebkitRegionFragment:
3080#endif
3081    case CSSPropertyWebkitRtlOrdering:
3082    case CSSPropertyWebkitRubyPosition:
3083#if ENABLE(CSS3_TEXT)
3084    case CSSPropertyWebkitTextAlignLast:
3085#endif // CSS3_TEXT
3086    case CSSPropertyWebkitTextCombine:
3087    case CSSPropertyWebkitTextEmphasisPosition:
3088#if ENABLE(CSS3_TEXT)
3089    case CSSPropertyWebkitTextJustify:
3090#endif // CSS3_TEXT
3091    case CSSPropertyWebkitTextSecurity:
3092    case CSSPropertyWebkitTransformStyle:
3093    case CSSPropertyWebkitUserDrag:
3094    case CSSPropertyWebkitUserModify:
3095    case CSSPropertyWebkitUserSelect:
3096#if ENABLE(CSS_EXCLUSIONS)
3097    case CSSPropertyWebkitWrapFlow:
3098    case CSSPropertyWebkitWrapThrough:
3099#endif
3100    case CSSPropertyWebkitWritingMode:
3101    case CSSPropertyWhiteSpace:
3102    case CSSPropertyWordBreak:
3103    case CSSPropertyWordWrap:
3104        // These properties should be handled before in isValidKeywordPropertyAndValue().
3105        ASSERT_NOT_REACHED();
3106        return false;
3107#if ENABLE(CSS_DEVICE_ADAPTATION)
3108    // Properties bellow are validated inside parseViewportProperty, because we
3109    // check for parser state inViewportScope. We need to invalidate if someone
3110    // adds them outside a @viewport rule.
3111    case CSSPropertyMaxZoom:
3112    case CSSPropertyMinZoom:
3113    case CSSPropertyOrientation:
3114    case CSSPropertyUserZoom:
3115        validPrimitive = false;
3116        break;
3117#endif
3118#if ENABLE(SVG)
3119    default:
3120        return parseSVGValue(propId, important);
3121#endif
3122    }
3123
3124    if (validPrimitive) {
3125        parsedValue = parseValidPrimitive(id, value);
3126        m_valueList->next();
3127    }
3128    ASSERT(!m_parsedCalculation);
3129    if (parsedValue) {
3130        if (!m_valueList->current() || inShorthand()) {
3131            addProperty(propId, parsedValue.release(), important);
3132            return true;
3133        }
3134    }
3135    return false;
3136}
3137
3138void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
3139{
3140    if (lval) {
3141        if (lval->isBaseValueList())
3142            static_cast<CSSValueList*>(lval.get())->append(rval);
3143        else {
3144            PassRefPtr<CSSValue> oldlVal(lval.release());
3145            PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
3146            list->append(oldlVal);
3147            list->append(rval);
3148            lval = list;
3149        }
3150    }
3151    else
3152        lval = rval;
3153}
3154
3155static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue)
3156{
3157    if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
3158        || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
3159        cssValue = cssValuePool().createIdentifierValue(parserValue->id);
3160        return true;
3161    }
3162    return false;
3163}
3164
3165bool CSSParser::useLegacyBackgroundSizeShorthandBehavior() const
3166{
3167    return m_context.useLegacyBackgroundSizeShorthandBehavior;
3168}
3169
3170const int cMaxFillProperties = 9;
3171
3172bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
3173{
3174    ASSERT(numProperties <= cMaxFillProperties);
3175    if (numProperties > cMaxFillProperties)
3176        return false;
3177
3178    ShorthandScope scope(this, propId);
3179
3180    bool parsedProperty[cMaxFillProperties] = { false };
3181    RefPtr<CSSValue> values[cMaxFillProperties];
3182    RefPtr<CSSValue> clipValue;
3183    RefPtr<CSSValue> positionYValue;
3184    RefPtr<CSSValue> repeatYValue;
3185    bool foundClip = false;
3186    int i;
3187    bool foundPositionCSSProperty = false;
3188
3189    while (m_valueList->current()) {
3190        CSSParserValue* val = m_valueList->current();
3191        if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3192            // We hit the end.  Fill in all remaining values with the initial value.
3193            m_valueList->next();
3194            for (i = 0; i < numProperties; ++i) {
3195                if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
3196                    // Color is not allowed except as the last item in a list for backgrounds.
3197                    // Reject the entire property.
3198                    return false;
3199
3200                if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
3201                    addFillValue(values[i], cssValuePool().createImplicitInitialValue());
3202                    if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
3203                        addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
3204                    if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
3205                        addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
3206                    if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
3207                        // If background-origin wasn't present, then reset background-clip also.
3208                        addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
3209                    }
3210                }
3211                parsedProperty[i] = false;
3212            }
3213            if (!m_valueList->current())
3214                break;
3215        }
3216
3217        bool sizeCSSPropertyExpected = false;
3218        if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
3219            sizeCSSPropertyExpected = true;
3220            m_valueList->next();
3221        }
3222
3223        foundPositionCSSProperty = false;
3224        bool found = false;
3225        for (i = 0; !found && i < numProperties; ++i) {
3226
3227            if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgroundSize && properties[i] != CSSPropertyWebkitMaskSize))
3228                continue;
3229            if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgroundSize || properties[i] == CSSPropertyWebkitMaskSize))
3230                continue;
3231
3232            if (!parsedProperty[i]) {
3233                RefPtr<CSSValue> val1;
3234                RefPtr<CSSValue> val2;
3235                CSSPropertyID propId1, propId2;
3236                CSSParserValue* parserValue = m_valueList->current();
3237                if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
3238                    parsedProperty[i] = found = true;
3239                    addFillValue(values[i], val1.release());
3240                    if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
3241                        addFillValue(positionYValue, val2.release());
3242                    if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
3243                        addFillValue(repeatYValue, val2.release());
3244                    if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
3245                        // Reparse the value as a clip, and see if we succeed.
3246                        if (parseBackgroundClip(parserValue, val1))
3247                            addFillValue(clipValue, val1.release()); // The property parsed successfully.
3248                        else
3249                            addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
3250                    }
3251                    if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
3252                        // Update clipValue
3253                        addFillValue(clipValue, val1.release());
3254                        foundClip = true;
3255                    }
3256                    if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
3257                        foundPositionCSSProperty = true;
3258                }
3259            }
3260        }
3261
3262        // if we didn't find at least one match, this is an
3263        // invalid shorthand and we have to ignore it
3264        if (!found)
3265            return false;
3266    }
3267
3268    // Now add all of the properties we found.
3269    for (i = 0; i < numProperties; i++) {
3270        // Fill in any remaining properties with the initial value.
3271        if (!parsedProperty[i]) {
3272            addFillValue(values[i], cssValuePool().createImplicitInitialValue());
3273            if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
3274                addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
3275            if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
3276                addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
3277            if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
3278                // If background-origin wasn't present, then reset background-clip also.
3279                addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
3280            }
3281        }
3282        if (properties[i] == CSSPropertyBackgroundPosition) {
3283            addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
3284            // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
3285            addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
3286        } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
3287            addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
3288            // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
3289            addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
3290        } else if (properties[i] == CSSPropertyBackgroundRepeat) {
3291            addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
3292            // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
3293            addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
3294        } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
3295            addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
3296            // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
3297            addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
3298        } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
3299            // Value is already set while updating origin
3300            continue;
3301        else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i] && useLegacyBackgroundSizeShorthandBehavior())
3302            continue;
3303        else
3304            addProperty(properties[i], values[i].release(), important);
3305
3306        // Add in clip values when we hit the corresponding origin property.
3307        if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
3308            addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
3309        else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
3310            addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
3311    }
3312
3313    return true;
3314}
3315
3316#if ENABLE(CSS_VARIABLES)
3317bool CSSParser::cssVariablesEnabled() const
3318{
3319    return m_context.isCSSVariablesEnabled;
3320}
3321
3322void CSSParser::storeVariableDeclaration(const CSSParserString& name, PassOwnPtr<CSSParserValueList> value, bool important)
3323{
3324    // When CSSGrammar.y encounters an invalid declaration it passes null for the CSSParserValueList, just bail.
3325    if (!value)
3326        return;
3327
3328    static const unsigned prefixLength = sizeof("-webkit-var-") - 1;
3329
3330    ASSERT(name.length() > prefixLength);
3331    AtomicString variableName = name.substring(prefixLength, name.length() - prefixLength);
3332
3333    StringBuilder builder;
3334    for (unsigned i = 0, size = value->size(); i < size; i++) {
3335        if (i)
3336            builder.append(' ');
3337        RefPtr<CSSValue> cssValue = value->valueAt(i)->createCSSValue();
3338        if (!cssValue)
3339            return;
3340        builder.append(cssValue->cssText());
3341    }
3342    addProperty(CSSPropertyVariable, CSSVariableValue::create(variableName, builder.toString().lower()), important, false);
3343}
3344#endif
3345
3346void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
3347{
3348    if (lval) {
3349        if (lval->isValueList())
3350            static_cast<CSSValueList*>(lval.get())->append(rval);
3351        else {
3352            PassRefPtr<CSSValue> oldVal(lval.release());
3353            PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
3354            list->append(oldVal);
3355            list->append(rval);
3356            lval = list;
3357        }
3358    }
3359    else
3360        lval = rval;
3361}
3362
3363bool CSSParser::parseAnimationShorthand(bool important)
3364{
3365    const StylePropertyShorthand& animationProperties = webkitAnimationShorthandForParsing();
3366    const unsigned numProperties = 7;
3367
3368    // The list of properties in the shorthand should be the same
3369    // length as the list with animation name in last position, even though they are
3370    // in a different order.
3371    ASSERT(numProperties == webkitAnimationShorthandForParsing().length());
3372    ASSERT(numProperties == webkitAnimationShorthand().length());
3373
3374    ShorthandScope scope(this, CSSPropertyWebkitAnimation);
3375
3376    bool parsedProperty[numProperties] = { false };
3377    AnimationParseContext context;
3378    RefPtr<CSSValue> values[numProperties];
3379
3380    unsigned i;
3381    while (m_valueList->current()) {
3382        CSSParserValue* val = m_valueList->current();
3383        if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3384            // We hit the end.  Fill in all remaining values with the initial value.
3385            m_valueList->next();
3386            for (i = 0; i < numProperties; ++i) {
3387                if (!parsedProperty[i])
3388                    addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3389                parsedProperty[i] = false;
3390            }
3391            if (!m_valueList->current())
3392                break;
3393            context.commitFirstAnimation();
3394        }
3395
3396        bool found = false;
3397        for (i = 0; i < numProperties; ++i) {
3398            if (!parsedProperty[i]) {
3399                RefPtr<CSSValue> val;
3400                if (parseAnimationProperty(animationProperties.properties()[i], val, context)) {
3401                    parsedProperty[i] = found = true;
3402                    addAnimationValue(values[i], val.release());
3403                    break;
3404                }
3405            }
3406
3407            // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid.
3408            if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation())
3409                return false;
3410        }
3411
3412        // if we didn't find at least one match, this is an
3413        // invalid shorthand and we have to ignore it
3414        if (!found)
3415            return false;
3416    }
3417
3418    for (i = 0; i < numProperties; ++i) {
3419        // If we didn't find the property, set an intial value.
3420        if (!parsedProperty[i])
3421            addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3422
3423        addProperty(animationProperties.properties()[i], values[i].release(), important);
3424    }
3425
3426    return true;
3427}
3428
3429bool CSSParser::parseTransitionShorthand(CSSPropertyID propId, bool important)
3430{
3431    const unsigned numProperties = 4;
3432    const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
3433    ASSERT(numProperties == shorthand.length());
3434
3435    ShorthandScope scope(this, propId);
3436
3437    bool parsedProperty[numProperties] = { false };
3438    AnimationParseContext context;
3439    RefPtr<CSSValue> values[numProperties];
3440
3441    unsigned i;
3442    while (m_valueList->current()) {
3443        CSSParserValue* val = m_valueList->current();
3444        if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3445            // We hit the end. Fill in all remaining values with the initial value.
3446            m_valueList->next();
3447            for (i = 0; i < numProperties; ++i) {
3448                if (!parsedProperty[i])
3449                    addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3450                parsedProperty[i] = false;
3451            }
3452            if (!m_valueList->current())
3453                break;
3454            context.commitFirstAnimation();
3455        }
3456
3457        bool found = false;
3458        for (i = 0; !found && i < numProperties; ++i) {
3459            if (!parsedProperty[i]) {
3460                RefPtr<CSSValue> val;
3461                if (parseAnimationProperty(shorthand.properties()[i], val, context)) {
3462                    parsedProperty[i] = found = true;
3463                    addAnimationValue(values[i], val.release());
3464                }
3465
3466                // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid.
3467                if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation())
3468                    return false;
3469            }
3470        }
3471
3472        // if we didn't find at least one match, this is an
3473        // invalid shorthand and we have to ignore it
3474        if (!found)
3475            return false;
3476    }
3477
3478    // Fill in any remaining properties with the initial value.
3479    for (i = 0; i < numProperties; ++i) {
3480        if (!parsedProperty[i])
3481            addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3482    }
3483
3484    // Now add all of the properties we found.
3485    for (i = 0; i < numProperties; i++)
3486        addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].release(), important);
3487
3488    return true;
3489}
3490
3491bool CSSParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
3492{
3493    // We try to match as many properties as possible
3494    // We set up an array of booleans to mark which property has been found,
3495    // and we try to search for properties until it makes no longer any sense.
3496    ShorthandScope scope(this, propId);
3497
3498    bool found = false;
3499    unsigned propertiesParsed = 0;
3500    bool propertyFound[6]= { false, false, false, false, false, false }; // 6 is enough size.
3501
3502    while (m_valueList->current()) {
3503        found = false;
3504        for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
3505            if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
3506                    propertyFound[propIndex] = found = true;
3507                    propertiesParsed++;
3508            }
3509        }
3510
3511        // if we didn't find at least one match, this is an
3512        // invalid shorthand and we have to ignore it
3513        if (!found)
3514            return false;
3515    }
3516
3517    if (propertiesParsed == shorthand.length())
3518        return true;
3519
3520    // Fill in any remaining properties with the initial value.
3521    ImplicitScope implicitScope(this, PropertyImplicit);
3522    const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization();
3523    for (unsigned i = 0; i < shorthand.length(); ++i) {
3524        if (propertyFound[i])
3525            continue;
3526
3527        if (propertiesForInitialization) {
3528            const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]);
3529            for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
3530                addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
3531        } else
3532            addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
3533    }
3534
3535    return true;
3536}
3537
3538bool CSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties,  bool important)
3539{
3540    /* From the CSS 2 specs, 8.3
3541     * If there is only one value, it applies to all sides. If there are two values, the top and
3542     * bottom margins are set to the first value and the right and left margins are set to the second.
3543     * If there are three values, the top is set to the first value, the left and right are set to the
3544     * second, and the bottom is set to the third. If there are four values, they apply to the top,
3545     * right, bottom, and left, respectively.
3546     */
3547
3548    int num = inShorthand() ? 1 : m_valueList->size();
3549
3550    ShorthandScope scope(this, propId);
3551
3552    // the order is top, right, bottom, left
3553    switch (num) {
3554        case 1: {
3555            if (!parseValue(properties[0], important))
3556                return false;
3557            CSSValue* value = m_parsedProperties.last().value();
3558            ImplicitScope implicitScope(this, PropertyImplicit);
3559            addProperty(properties[1], value, important);
3560            addProperty(properties[2], value, important);
3561            addProperty(properties[3], value, important);
3562            break;
3563        }
3564        case 2: {
3565            if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
3566                return false;
3567            CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3568            ImplicitScope implicitScope(this, PropertyImplicit);
3569            addProperty(properties[2], value, important);
3570            value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3571            addProperty(properties[3], value, important);
3572            break;
3573        }
3574        case 3: {
3575            if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
3576                return false;
3577            CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3578            ImplicitScope implicitScope(this, PropertyImplicit);
3579            addProperty(properties[3], value, important);
3580            break;
3581        }
3582        case 4: {
3583            if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
3584                !parseValue(properties[2], important) || !parseValue(properties[3], important))
3585                return false;
3586            break;
3587        }
3588        default: {
3589            return false;
3590        }
3591    }
3592
3593    return true;
3594}
3595
3596// auto | <identifier>
3597bool CSSParser::parsePage(CSSPropertyID propId, bool important)
3598{
3599    ASSERT(propId == CSSPropertyPage);
3600
3601    if (m_valueList->size() != 1)
3602        return false;
3603
3604    CSSParserValue* value = m_valueList->current();
3605    if (!value)
3606        return false;
3607
3608    if (value->id == CSSValueAuto) {
3609        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
3610        return true;
3611    } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
3612        addProperty(propId, createPrimitiveStringValue(value), important);
3613        return true;
3614    }
3615    return false;
3616}
3617
3618// <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
3619bool CSSParser::parseSize(CSSPropertyID propId, bool important)
3620{
3621    ASSERT(propId == CSSPropertySize);
3622
3623    if (m_valueList->size() > 2)
3624        return false;
3625
3626    CSSParserValue* value = m_valueList->current();
3627    if (!value)
3628        return false;
3629
3630    RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
3631
3632    // First parameter.
3633    SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
3634    if (paramType == None)
3635        return false;
3636
3637    // Second parameter, if any.
3638    value = m_valueList->next();
3639    if (value) {
3640        paramType = parseSizeParameter(parsedValues.get(), value, paramType);
3641        if (paramType == None)
3642            return false;
3643    }
3644
3645    addProperty(propId, parsedValues.release(), important);
3646    return true;
3647}
3648
3649CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
3650{
3651    switch (value->id) {
3652    case CSSValueAuto:
3653        if (prevParamType == None) {
3654            parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3655            return Auto;
3656        }
3657        return None;
3658    case CSSValueLandscape:
3659    case CSSValuePortrait:
3660        if (prevParamType == None || prevParamType == PageSize) {
3661            parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3662            return Orientation;
3663        }
3664        return None;
3665    case CSSValueA3:
3666    case CSSValueA4:
3667    case CSSValueA5:
3668    case CSSValueB4:
3669    case CSSValueB5:
3670    case CSSValueLedger:
3671    case CSSValueLegal:
3672    case CSSValueLetter:
3673        if (prevParamType == None || prevParamType == Orientation) {
3674            // Normalize to Page Size then Orientation order by prepending.
3675            // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
3676            parsedValues->prepend(cssValuePool().createIdentifierValue(value->id));
3677            return PageSize;
3678        }
3679        return None;
3680    case 0:
3681        if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) {
3682            parsedValues->append(createPrimitiveNumericValue(value));
3683            return Length;
3684        }
3685        return None;
3686    default:
3687        return None;
3688    }
3689}
3690
3691// [ <string> <string> ]+ | inherit | none
3692// inherit and none are handled in parseValue.
3693bool CSSParser::parseQuotes(CSSPropertyID propId, bool important)
3694{
3695    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3696    while (CSSParserValue* val = m_valueList->current()) {
3697        RefPtr<CSSValue> parsedValue;
3698        if (val->unit == CSSPrimitiveValue::CSS_STRING)
3699            parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
3700        else
3701            break;
3702        values->append(parsedValue.release());
3703        m_valueList->next();
3704    }
3705    if (values->length()) {
3706        addProperty(propId, values.release(), important);
3707        m_valueList->next();
3708        return true;
3709    }
3710    return false;
3711}
3712
3713// [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
3714// in CSS 2.1 this got somewhat reduced:
3715// [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
3716bool CSSParser::parseContent(CSSPropertyID propId, bool important)
3717{
3718    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3719
3720    while (CSSParserValue* val = m_valueList->current()) {
3721        RefPtr<CSSValue> parsedValue;
3722        if (val->unit == CSSPrimitiveValue::CSS_URI) {
3723            // url
3724            parsedValue = CSSImageValue::create(completeURL(val->string));
3725        } else if (val->unit == CSSParserValue::Function) {
3726            // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
3727            CSSParserValueList* args = val->function->args.get();
3728            if (!args)
3729                return false;
3730            if (equalIgnoringCase(val->function->name, "attr(")) {
3731                parsedValue = parseAttr(args);
3732                if (!parsedValue)
3733                    return false;
3734            } else if (equalIgnoringCase(val->function->name, "counter(")) {
3735                parsedValue = parseCounterContent(args, false);
3736                if (!parsedValue)
3737                    return false;
3738            } else if (equalIgnoringCase(val->function->name, "counters(")) {
3739                parsedValue = parseCounterContent(args, true);
3740                if (!parsedValue)
3741                    return false;
3742#if ENABLE(CSS_IMAGE_SET)
3743            } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
3744                parsedValue = parseImageSet();
3745                if (!parsedValue)
3746                    return false;
3747#endif
3748            } else if (isGeneratedImageValue(val)) {
3749                if (!parseGeneratedImage(m_valueList.get(), parsedValue))
3750                    return false;
3751            } else
3752                return false;
3753        } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
3754            // open-quote
3755            // close-quote
3756            // no-open-quote
3757            // no-close-quote
3758            // inherit
3759            // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
3760            // none
3761            // normal
3762            switch (val->id) {
3763            case CSSValueOpenQuote:
3764            case CSSValueCloseQuote:
3765            case CSSValueNoOpenQuote:
3766            case CSSValueNoCloseQuote:
3767            case CSSValueNone:
3768            case CSSValueNormal:
3769                parsedValue = cssValuePool().createIdentifierValue(val->id);
3770            }
3771        } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
3772            parsedValue = createPrimitiveStringValue(val);
3773        }
3774        if (!parsedValue)
3775            break;
3776        values->append(parsedValue.release());
3777        m_valueList->next();
3778    }
3779
3780    if (values->length()) {
3781        addProperty(propId, values.release(), important);
3782        m_valueList->next();
3783        return true;
3784    }
3785
3786    return false;
3787}
3788
3789PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args)
3790{
3791    if (args->size() != 1)
3792        return 0;
3793
3794    CSSParserValue* a = args->current();
3795
3796    if (a->unit != CSSPrimitiveValue::CSS_IDENT)
3797        return 0;
3798
3799    String attrName = a->string;
3800    // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
3801    // But HTML attribute names can't have those characters, and we should not
3802    // even parse them inside attr().
3803    if (attrName[0] == '-')
3804        return 0;
3805
3806    if (m_context.isHTMLDocument)
3807        attrName = attrName.lower();
3808
3809    return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
3810}
3811
3812PassRefPtr<CSSValue> CSSParser::parseBackgroundColor()
3813{
3814    int id = m_valueList->current()->id;
3815    if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
3816        (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
3817        return cssValuePool().createIdentifierValue(id);
3818    return parseColor();
3819}
3820
3821bool CSSParser::parseFillImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
3822{
3823    if (valueList->current()->id == CSSValueNone) {
3824        value = cssValuePool().createIdentifierValue(CSSValueNone);
3825        return true;
3826    }
3827    if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
3828        value = CSSImageValue::create(completeURL(valueList->current()->string));
3829        return true;
3830    }
3831
3832    if (isGeneratedImageValue(valueList->current()))
3833        return parseGeneratedImage(valueList, value);
3834
3835#if ENABLE(CSS_IMAGE_SET)
3836    if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) {
3837        value = parseImageSet();
3838        if (value)
3839            return true;
3840    }
3841#endif
3842
3843    return false;
3844}
3845
3846PassRefPtr<CSSValue> CSSParser::parseFillPositionX(CSSParserValueList* valueList)
3847{
3848    int id = valueList->current()->id;
3849    if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
3850        int percent = 0;
3851        if (id == CSSValueRight)
3852            percent = 100;
3853        else if (id == CSSValueCenter)
3854            percent = 50;
3855        return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3856    }
3857    if (validUnit(valueList->current(), FPercent | FLength))
3858        return createPrimitiveNumericValue(valueList->current());
3859    return 0;
3860}
3861
3862PassRefPtr<CSSValue> CSSParser::parseFillPositionY(CSSParserValueList* valueList)
3863{
3864    int id = valueList->current()->id;
3865    if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
3866        int percent = 0;
3867        if (id == CSSValueBottom)
3868            percent = 100;
3869        else if (id == CSSValueCenter)
3870            percent = 50;
3871        return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3872    }
3873    if (validUnit(valueList->current(), FPercent | FLength))
3874        return createPrimitiveNumericValue(valueList->current());
3875    return 0;
3876}
3877
3878PassRefPtr<CSSPrimitiveValue> CSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode)
3879{
3880    int id = valueList->current()->id;
3881    if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
3882        int percent = 0;
3883        if (id == CSSValueLeft || id == CSSValueRight) {
3884            if (cumulativeFlags & XFillPosition)
3885                return 0;
3886            cumulativeFlags |= XFillPosition;
3887            individualFlag = XFillPosition;
3888            if (id == CSSValueRight)
3889                percent = 100;
3890        }
3891        else if (id == CSSValueTop || id == CSSValueBottom) {
3892            if (cumulativeFlags & YFillPosition)
3893                return 0;
3894            cumulativeFlags |= YFillPosition;
3895            individualFlag = YFillPosition;
3896            if (id == CSSValueBottom)
3897                percent = 100;
3898        } else if (id == CSSValueCenter) {
3899            // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
3900            percent = 50;
3901            cumulativeFlags |= AmbiguousFillPosition;
3902            individualFlag = AmbiguousFillPosition;
3903        }
3904
3905        if (parsingMode == ResolveValuesAsKeyword)
3906            return cssValuePool().createIdentifierValue(id);
3907
3908        return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3909    }
3910    if (validUnit(valueList->current(), FPercent | FLength)) {
3911        if (!cumulativeFlags) {
3912            cumulativeFlags |= XFillPosition;
3913            individualFlag = XFillPosition;
3914        } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
3915            cumulativeFlags |= YFillPosition;
3916            individualFlag = YFillPosition;
3917        } else {
3918            if (m_parsedCalculation)
3919                m_parsedCalculation.release();
3920            return 0;
3921        }
3922        return createPrimitiveNumericValue(valueList->current());
3923    }
3924    return 0;
3925}
3926
3927static bool isValueConflictingWithCurrentEdge(int value1, int value2)
3928{
3929    if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSValueLeft || value2 == CSSValueRight))
3930        return true;
3931
3932    if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSValueTop || value2 == CSSValueBottom))
3933        return true;
3934
3935    return false;
3936}
3937
3938static bool isFillPositionKeyword(int value)
3939{
3940    return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter;
3941}
3942
3943void CSSParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtr<CSSPrimitiveValue> parsedValue1, PassRefPtr<CSSPrimitiveValue> parsedValue2)
3944{
3945    // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <percentage> | <length> ]
3946    // In the case of 4 values <position> requires the second value to be a length or a percentage.
3947    if (isFillPositionKeyword(parsedValue2->getIdent()))
3948        return;
3949
3950    unsigned cumulativeFlags = 0;
3951    FillPositionFlag value3Flag = InvalidFillPosition;
3952    RefPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
3953    if (!value3)
3954        return;
3955
3956    int ident1 = parsedValue1->getIdent();
3957    int ident3 = value3->getIdent();
3958
3959    if (ident1 == CSSValueCenter)
3960        return;
3961
3962    if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
3963        return;
3964
3965    // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
3966    // needed as the second call to parseFillPositionComponent was on purpose not checking it. In the
3967    // case of two values top 20px is invalid but in the case of 4 values it becomes valid.
3968    if (isValueConflictingWithCurrentEdge(ident1, ident3))
3969        return;
3970
3971    valueList->next();
3972
3973    cumulativeFlags = 0;
3974    FillPositionFlag value4Flag = InvalidFillPosition;
3975    RefPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(valueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
3976    if (!value4)
3977        return;
3978
3979    // 4th value must be a length or a percentage.
3980    if (isFillPositionKeyword(value4->getIdent()))
3981        return;
3982
3983    value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
3984    value2 = createPrimitiveValuePair(value3, value4);
3985
3986    if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
3987        value1.swap(value2);
3988
3989    valueList->next();
3990}
3991void CSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtr<CSSPrimitiveValue> parsedValue1, PassRefPtr<CSSPrimitiveValue> parsedValue2)
3992{
3993    unsigned cumulativeFlags = 0;
3994    FillPositionFlag value3Flag = InvalidFillPosition;
3995    RefPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
3996
3997    // value3 is not an expected value, we return.
3998    if (!value3)
3999        return;
4000
4001    valueList->next();
4002
4003    bool swapNeeded = false;
4004    int ident1 = parsedValue1->getIdent();
4005    int ident2 = parsedValue2->getIdent();
4006    int ident3 = value3->getIdent();
4007
4008    int firstPositionKeyword;
4009    int secondPositionKeyword;
4010
4011    if (ident1 == CSSValueCenter) {
4012        // <position> requires the first 'center' to be followed by a keyword.
4013        if (!isFillPositionKeyword(ident2))
4014            return;
4015
4016        // If 'center' is the first keyword then the last one needs to be a length.
4017        if (isFillPositionKeyword(ident3))
4018            return;
4019
4020        firstPositionKeyword = CSSValueLeft;
4021        if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
4022            firstPositionKeyword = CSSValueTop;
4023            swapNeeded = true;
4024        }
4025        value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
4026        value2 = createPrimitiveValuePair(parsedValue2, value3);
4027    } else if (ident3 == CSSValueCenter) {
4028        if (isFillPositionKeyword(ident2))
4029            return;
4030
4031        secondPositionKeyword = CSSValueTop;
4032        if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
4033            secondPositionKeyword = CSSValueLeft;
4034            swapNeeded = true;
4035        }
4036        value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
4037        value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
4038    } else {
4039        RefPtr<CSSPrimitiveValue> firstPositionValue;
4040        RefPtr<CSSPrimitiveValue> secondPositionValue;
4041
4042        if (isFillPositionKeyword(ident2)) {
4043            // To match CSS grammar, we should only accept: [ center | left | right | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ].
4044            ASSERT(ident2 != CSSValueCenter);
4045
4046            if (isFillPositionKeyword(ident3))
4047                return;
4048
4049            secondPositionValue = value3;
4050            secondPositionKeyword = ident2;
4051            firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
4052        } else {
4053            // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
4054            if (!isFillPositionKeyword(ident3))
4055                return;
4056
4057            firstPositionValue = parsedValue2;
4058            secondPositionKeyword = ident3;
4059            secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
4060        }
4061
4062        if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
4063            return;
4064
4065        value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue);
4066        value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue);
4067    }
4068
4069    if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
4070        value1.swap(value2);
4071
4072#ifndef NDEBUG
4073    CSSPrimitiveValue* first = static_cast<CSSPrimitiveValue*>(value1.get());
4074    CSSPrimitiveValue* second = static_cast<CSSPrimitiveValue*>(value2.get());
4075    ident1 = first->getPairValue()->first()->getIdent();
4076    ident2 = second->getPairValue()->first()->getIdent();
4077    ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
4078    ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
4079#endif
4080}
4081
4082inline bool CSSParser::isPotentialPositionValue(CSSParserValue* value)
4083{
4084    return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue);
4085}
4086
4087void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
4088{
4089    unsigned numberOfValues = 0;
4090    for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++numberOfValues) {
4091        CSSParserValue* current = valueList->valueAt(i);
4092        if (isComma(current) || !current || isForwardSlashOperator(current) || !isPotentialPositionValue(current))
4093            break;
4094    }
4095
4096    if (numberOfValues > 4)
4097        return;
4098
4099    // If we are parsing two values, we can safely call the CSS 2.1 parsing function and return.
4100    if (numberOfValues <= 2) {
4101        parse2ValuesFillPosition(valueList, value1, value2);
4102        return;
4103    }
4104
4105    ASSERT(numberOfValues > 2 && numberOfValues <= 4);
4106
4107    CSSParserValue* value = valueList->current();
4108
4109    // <position> requires the first value to be a background keyword.
4110    if (!isFillPositionKeyword(value->id))
4111        return;
4112
4113    // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
4114    unsigned cumulativeFlags = 0;
4115    FillPositionFlag value1Flag = InvalidFillPosition;
4116    FillPositionFlag value2Flag = InvalidFillPosition;
4117    value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
4118    if (!value1)
4119        return;
4120
4121    value = valueList->next();
4122
4123    // In case we are parsing more than two values, relax the check inside of parseFillPositionComponent. top 20px is
4124    // a valid start for <position>.
4125    cumulativeFlags = AmbiguousFillPosition;
4126    value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
4127    if (value2)
4128        valueList->next();
4129    else {
4130        value1.clear();
4131        return;
4132    }
4133
4134    RefPtr<CSSPrimitiveValue> parsedValue1 = static_cast<CSSPrimitiveValue*>(value1.get());
4135    RefPtr<CSSPrimitiveValue> parsedValue2 = static_cast<CSSPrimitiveValue*>(value2.get());
4136
4137    value1.clear();
4138    value2.clear();
4139
4140    // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
4141    if (parsedValue2->getIdent() == CSSValueCenter)
4142        return;
4143
4144    if (numberOfValues == 3)
4145        parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
4146    else
4147        parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
4148}
4149
4150void CSSParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
4151{
4152    CSSParserValue* value = valueList->current();
4153
4154    // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
4155    unsigned cumulativeFlags = 0;
4156    FillPositionFlag value1Flag = InvalidFillPosition;
4157    FillPositionFlag value2Flag = InvalidFillPosition;
4158    value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
4159    if (!value1)
4160        return;
4161
4162    // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
4163    // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
4164    // value was explicitly specified for our property.
4165    value = valueList->next();
4166
4167    // First check for the comma.  If so, we are finished parsing this value or value pair.
4168    if (isComma(value))
4169        value = 0;
4170
4171    if (value) {
4172        value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
4173        if (value2)
4174            valueList->next();
4175        else {
4176            if (!inShorthand()) {
4177                value1.clear();
4178                return;
4179            }
4180        }
4181    }
4182
4183    if (!value2)
4184        // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
4185        // is simply 50%. This is our default.
4186        // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
4187        // For left/right/center, the default of 50% in the y is still correct.
4188        value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
4189
4190    if (value1Flag == YFillPosition || value2Flag == XFillPosition)
4191        value1.swap(value2);
4192}
4193
4194void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
4195{
4196    int id = m_valueList->current()->id;
4197    if (id == CSSValueRepeatX) {
4198        m_implicitShorthand = true;
4199        value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
4200        value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
4201        m_valueList->next();
4202        return;
4203    }
4204    if (id == CSSValueRepeatY) {
4205        m_implicitShorthand = true;
4206        value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
4207        value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
4208        m_valueList->next();
4209        return;
4210    }
4211    if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
4212        value1 = cssValuePool().createIdentifierValue(id);
4213    else {
4214        value1 = 0;
4215        return;
4216    }
4217
4218    CSSParserValue* value = m_valueList->next();
4219
4220    // Parse the second value if one is available
4221    if (value && !isComma(value)) {
4222        id = value->id;
4223        if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
4224            value2 = cssValuePool().createIdentifierValue(id);
4225            m_valueList->next();
4226            return;
4227        }
4228    }
4229
4230    // If only one value was specified, value2 is the same as value1.
4231    m_implicitShorthand = true;
4232    value2 = cssValuePool().createIdentifierValue(static_cast<CSSPrimitiveValue*>(value1.get())->getIdent());
4233}
4234
4235PassRefPtr<CSSValue> CSSParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
4236{
4237    allowComma = true;
4238    CSSParserValue* value = m_valueList->current();
4239
4240    if (value->id == CSSValueContain || value->id == CSSValueCover)
4241        return cssValuePool().createIdentifierValue(value->id);
4242
4243    RefPtr<CSSPrimitiveValue> parsedValue1;
4244
4245    if (value->id == CSSValueAuto)
4246        parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
4247    else {
4248        if (!validUnit(value, FLength | FPercent))
4249            return 0;
4250        parsedValue1 = createPrimitiveNumericValue(value);
4251    }
4252
4253    RefPtr<CSSPrimitiveValue> parsedValue2;
4254    if ((value = m_valueList->next())) {
4255        if (value->unit == CSSParserValue::Operator && value->iValue == ',')
4256            allowComma = false;
4257        else if (value->id != CSSValueAuto) {
4258            if (!validUnit(value, FLength | FPercent)) {
4259                if (!inShorthand())
4260                    return 0;
4261                // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
4262                m_valueList->previous();
4263            } else
4264                parsedValue2 = createPrimitiveNumericValue(value);
4265        }
4266    } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
4267        // For backwards compatibility we set the second value to the first if it is omitted.
4268        // We only need to do this for -webkit-background-size. It should be safe to let masks match
4269        // the real property.
4270        parsedValue2 = parsedValue1;
4271    }
4272
4273    if (!parsedValue2)
4274        return parsedValue1;
4275    return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release());
4276}
4277
4278bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
4279                                  RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
4280{
4281    RefPtr<CSSValueList> values;
4282    RefPtr<CSSValueList> values2;
4283    CSSParserValue* val;
4284    RefPtr<CSSValue> value;
4285    RefPtr<CSSValue> value2;
4286
4287    bool allowComma = false;
4288
4289    retValue1 = retValue2 = 0;
4290    propId1 = propId;
4291    propId2 = propId;
4292    if (propId == CSSPropertyBackgroundPosition) {
4293        propId1 = CSSPropertyBackgroundPositionX;
4294        propId2 = CSSPropertyBackgroundPositionY;
4295    } else if (propId == CSSPropertyWebkitMaskPosition) {
4296        propId1 = CSSPropertyWebkitMaskPositionX;
4297        propId2 = CSSPropertyWebkitMaskPositionY;
4298    } else if (propId == CSSPropertyBackgroundRepeat) {
4299        propId1 = CSSPropertyBackgroundRepeatX;
4300        propId2 = CSSPropertyBackgroundRepeatY;
4301    } else if (propId == CSSPropertyWebkitMaskRepeat) {
4302        propId1 = CSSPropertyWebkitMaskRepeatX;
4303        propId2 = CSSPropertyWebkitMaskRepeatY;
4304    }
4305
4306    while ((val = m_valueList->current())) {
4307        RefPtr<CSSValue> currValue;
4308        RefPtr<CSSValue> currValue2;
4309
4310        if (allowComma) {
4311            if (!isComma(val))
4312                return false;
4313            m_valueList->next();
4314            allowComma = false;
4315        } else {
4316            allowComma = true;
4317            switch (propId) {
4318                case CSSPropertyBackgroundColor:
4319                    currValue = parseBackgroundColor();
4320                    if (currValue)
4321                        m_valueList->next();
4322                    break;
4323                case CSSPropertyBackgroundAttachment:
4324                    if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
4325                        currValue = cssValuePool().createIdentifierValue(val->id);
4326                        m_valueList->next();
4327                    }
4328                    break;
4329                case CSSPropertyBackgroundImage:
4330                case CSSPropertyWebkitMaskImage:
4331                    if (parseFillImage(m_valueList.get(), currValue))
4332                        m_valueList->next();
4333                    break;
4334                case CSSPropertyWebkitBackgroundClip:
4335                case CSSPropertyWebkitBackgroundOrigin:
4336                case CSSPropertyWebkitMaskClip:
4337                case CSSPropertyWebkitMaskOrigin:
4338                    // The first three values here are deprecated and do not apply to the version of the property that has
4339                    // the -webkit- prefix removed.
4340                    if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
4341                        val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
4342                        ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
4343                         (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
4344                        currValue = cssValuePool().createIdentifierValue(val->id);
4345                        m_valueList->next();
4346                    }
4347                    break;
4348                case CSSPropertyBackgroundClip:
4349                    if (parseBackgroundClip(val, currValue))
4350                        m_valueList->next();
4351                    break;
4352                case CSSPropertyBackgroundOrigin:
4353                    if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
4354                        currValue = cssValuePool().createIdentifierValue(val->id);
4355                        m_valueList->next();
4356                    }
4357                    break;
4358                case CSSPropertyBackgroundPosition:
4359                case CSSPropertyWebkitMaskPosition:
4360                    parseFillPosition(m_valueList.get(), currValue, currValue2);
4361                    // parseFillPosition advances the m_valueList pointer.
4362                    break;
4363                case CSSPropertyBackgroundPositionX:
4364                case CSSPropertyWebkitMaskPositionX: {
4365                    currValue = parseFillPositionX(m_valueList.get());
4366                    if (currValue)
4367                        m_valueList->next();
4368                    break;
4369                }
4370                case CSSPropertyBackgroundPositionY:
4371                case CSSPropertyWebkitMaskPositionY: {
4372                    currValue = parseFillPositionY(m_valueList.get());
4373                    if (currValue)
4374                        m_valueList->next();
4375                    break;
4376                }
4377                case CSSPropertyWebkitBackgroundComposite:
4378                case CSSPropertyWebkitMaskComposite:
4379                    if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) {
4380                        currValue = cssValuePool().createIdentifierValue(val->id);
4381                        m_valueList->next();
4382                    }
4383                    break;
4384#if ENABLE(CSS_COMPOSITING)
4385                case CSSPropertyWebkitBackgroundBlendMode:
4386                    if (cssCompositingEnabled() && (val->id == CSSValueNormal || val->id == CSSValueMultiply
4387                        || val->id == CSSValueScreen || val->id == CSSValueOverlay || val->id == CSSValueDarken
4388                        || val->id == CSSValueLighten ||  val->id == CSSValueColorDodge || val->id == CSSValueColorBurn
4389                        || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference
4390                        || val->id == CSSValueExclusion || val->id == CSSValueHue || val->id == CSSValueSaturation
4391                        || val->id == CSSValueColor || val->id == CSSValueLuminosity)) {
4392                        currValue = cssValuePool().createIdentifierValue(val->id);
4393                        m_valueList->next();
4394                    }
4395                    break;
4396#endif
4397                case CSSPropertyBackgroundRepeat:
4398                case CSSPropertyWebkitMaskRepeat:
4399                    parseFillRepeat(currValue, currValue2);
4400                    // parseFillRepeat advances the m_valueList pointer
4401                    break;
4402                case CSSPropertyBackgroundSize:
4403                case CSSPropertyWebkitBackgroundSize:
4404                case CSSPropertyWebkitMaskSize: {
4405                    currValue = parseFillSize(propId, allowComma);
4406                    if (currValue)
4407                        m_valueList->next();
4408                    break;
4409                }
4410                default:
4411                    break;
4412            }
4413            if (!currValue)
4414                return false;
4415
4416            if (value && !values) {
4417                values = CSSValueList::createCommaSeparated();
4418                values->append(value.release());
4419            }
4420
4421            if (value2 && !values2) {
4422                values2 = CSSValueList::createCommaSeparated();
4423                values2->append(value2.release());
4424            }
4425
4426            if (values)
4427                values->append(currValue.release());
4428            else
4429                value = currValue.release();
4430            if (currValue2) {
4431                if (values2)
4432                    values2->append(currValue2.release());
4433                else
4434                    value2 = currValue2.release();
4435            }
4436        }
4437
4438        // When parsing any fill shorthand property, we let it handle building up the lists for all
4439        // properties.
4440        if (inShorthand())
4441            break;
4442    }
4443
4444    if (values && values->length()) {
4445        retValue1 = values.release();
4446        if (values2 && values2->length())
4447            retValue2 = values2.release();
4448        return true;
4449    }
4450    if (value) {
4451        retValue1 = value.release();
4452        retValue2 = value2.release();
4453        return true;
4454    }
4455    return false;
4456}
4457
4458PassRefPtr<CSSValue> CSSParser::parseAnimationDelay()
4459{
4460    CSSParserValue* value = m_valueList->current();
4461    if (validUnit(value, FTime))
4462        return createPrimitiveNumericValue(value);
4463    return 0;
4464}
4465
4466PassRefPtr<CSSValue> CSSParser::parseAnimationDirection()
4467{
4468    CSSParserValue* value = m_valueList->current();
4469    if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
4470        return cssValuePool().createIdentifierValue(value->id);
4471    return 0;
4472}
4473
4474PassRefPtr<CSSValue> CSSParser::parseAnimationDuration()
4475{
4476    CSSParserValue* value = m_valueList->current();
4477    if (validUnit(value, FTime | FNonNeg))
4478        return createPrimitiveNumericValue(value);
4479    return 0;
4480}
4481
4482PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode()
4483{
4484    CSSParserValue* value = m_valueList->current();
4485    if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
4486        return cssValuePool().createIdentifierValue(value->id);
4487    return 0;
4488}
4489
4490PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount()
4491{
4492    CSSParserValue* value = m_valueList->current();
4493    if (value->id == CSSValueInfinite)
4494        return cssValuePool().createIdentifierValue(value->id);
4495    if (validUnit(value, FNumber | FNonNeg))
4496        return createPrimitiveNumericValue(value);
4497    return 0;
4498}
4499
4500PassRefPtr<CSSValue> CSSParser::parseAnimationName()
4501{
4502    CSSParserValue* value = m_valueList->current();
4503    if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
4504        if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value, "none"))) {
4505            return cssValuePool().createIdentifierValue(CSSValueNone);
4506        } else {
4507            return createPrimitiveStringValue(value);
4508        }
4509    }
4510    return 0;
4511}
4512
4513PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState()
4514{
4515    CSSParserValue* value = m_valueList->current();
4516    if (value->id == CSSValueRunning || value->id == CSSValuePaused)
4517        return cssValuePool().createIdentifierValue(value->id);
4518    return 0;
4519}
4520
4521PassRefPtr<CSSValue> CSSParser::parseAnimationProperty(AnimationParseContext& context)
4522{
4523    CSSParserValue* value = m_valueList->current();
4524    if (value->unit != CSSPrimitiveValue::CSS_IDENT)
4525        return 0;
4526    int result = cssPropertyID(value->string);
4527    if (result)
4528        return cssValuePool().createIdentifierValue(result);
4529    if (equalIgnoringCase(value, "all")) {
4530        context.sawAnimationPropertyKeyword();
4531        return cssValuePool().createIdentifierValue(CSSValueAll);
4532    }
4533    if (equalIgnoringCase(value, "none")) {
4534        context.commitAnimationPropertyKeyword();
4535        context.sawAnimationPropertyKeyword();
4536        return cssValuePool().createIdentifierValue(CSSValueNone);
4537    }
4538    return 0;
4539}
4540
4541bool CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
4542{
4543    parse2ValuesFillPosition(m_valueList.get(), value1, value2);
4544
4545    // now get z
4546    if (m_valueList->current()) {
4547        if (validUnit(m_valueList->current(), FLength)) {
4548            value3 = createPrimitiveNumericValue(m_valueList->current());
4549            m_valueList->next();
4550            return true;
4551        }
4552        return false;
4553    }
4554    value3 = cssValuePool().createImplicitInitialValue();
4555    return true;
4556}
4557
4558bool CSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
4559{
4560    CSSParserValue* v = args->current();
4561    if (!validUnit(v, FNumber))
4562        return false;
4563    result = v->fValue;
4564    v = args->next();
4565    if (!v)
4566        // The last number in the function has no comma after it, so we're done.
4567        return true;
4568    if (!isComma(v))
4569        return false;
4570    args->next();
4571    return true;
4572}
4573
4574PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction()
4575{
4576    CSSParserValue* value = m_valueList->current();
4577    if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
4578        || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd)
4579        return cssValuePool().createIdentifierValue(value->id);
4580
4581    // We must be a function.
4582    if (value->unit != CSSParserValue::Function)
4583        return 0;
4584
4585    CSSParserValueList* args = value->function->args.get();
4586
4587    if (equalIgnoringCase(value->function->name, "steps(")) {
4588        // For steps, 1 or 2 params must be specified (comma-separated)
4589        if (!args || (args->size() != 1 && args->size() != 3))
4590            return 0;
4591
4592        // There are two values.
4593        int numSteps;
4594        bool stepAtStart = false;
4595
4596        CSSParserValue* v = args->current();
4597        if (!validUnit(v, FInteger))
4598            return 0;
4599        numSteps = clampToInteger(v->fValue);
4600        if (numSteps < 1)
4601            return 0;
4602        v = args->next();
4603
4604        if (v) {
4605            // There is a comma so we need to parse the second value
4606            if (!isComma(v))
4607                return 0;
4608            v = args->next();
4609            if (v->id != CSSValueStart && v->id != CSSValueEnd)
4610                return 0;
4611            stepAtStart = v->id == CSSValueStart;
4612        }
4613
4614        return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart);
4615    }
4616
4617    if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
4618        // For cubic bezier, 4 values must be specified.
4619        if (!args || args->size() != 7)
4620            return 0;
4621
4622        // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range.
4623        double x1, y1, x2, y2;
4624
4625        if (!parseCubicBezierTimingFunctionValue(args, x1))
4626            return 0;
4627        if (x1 < 0 || x1 > 1)
4628            return 0;
4629        if (!parseCubicBezierTimingFunctionValue(args, y1))
4630            return 0;
4631        if (!parseCubicBezierTimingFunctionValue(args, x2))
4632            return 0;
4633        if (x2 < 0 || x2 > 1)
4634            return 0;
4635        if (!parseCubicBezierTimingFunctionValue(args, y2))
4636            return 0;
4637
4638        return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
4639    }
4640
4641    return 0;
4642}
4643
4644bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& result, AnimationParseContext& context)
4645{
4646    RefPtr<CSSValueList> values;
4647    CSSParserValue* val;
4648    RefPtr<CSSValue> value;
4649    bool allowComma = false;
4650
4651    result = 0;
4652
4653    while ((val = m_valueList->current())) {
4654        RefPtr<CSSValue> currValue;
4655        if (allowComma) {
4656            if (!isComma(val))
4657                return false;
4658            m_valueList->next();
4659            allowComma = false;
4660        }
4661        else {
4662            switch (propId) {
4663                case CSSPropertyWebkitAnimationDelay:
4664                case CSSPropertyTransitionDelay:
4665                case CSSPropertyWebkitTransitionDelay:
4666                    currValue = parseAnimationDelay();
4667                    if (currValue)
4668                        m_valueList->next();
4669                    break;
4670                case CSSPropertyWebkitAnimationDirection:
4671                    currValue = parseAnimationDirection();
4672                    if (currValue)
4673                        m_valueList->next();
4674                    break;
4675                case CSSPropertyWebkitAnimationDuration:
4676                case CSSPropertyTransitionDuration:
4677                case CSSPropertyWebkitTransitionDuration:
4678                    currValue = parseAnimationDuration();
4679                    if (currValue)
4680                        m_valueList->next();
4681                    break;
4682                case CSSPropertyWebkitAnimationFillMode:
4683                    currValue = parseAnimationFillMode();
4684                    if (currValue)
4685                        m_valueList->next();
4686                    break;
4687                case CSSPropertyWebkitAnimationIterationCount:
4688                    currValue = parseAnimationIterationCount();
4689                    if (currValue)
4690                        m_valueList->next();
4691                    break;
4692                case CSSPropertyWebkitAnimationName:
4693                    currValue = parseAnimationName();
4694                    if (currValue)
4695                        m_valueList->next();
4696                    break;
4697                case CSSPropertyWebkitAnimationPlayState:
4698                    currValue = parseAnimationPlayState();
4699                    if (currValue)
4700                        m_valueList->next();
4701                    break;
4702                case CSSPropertyTransitionProperty:
4703                case CSSPropertyWebkitTransitionProperty:
4704                    currValue = parseAnimationProperty(context);
4705                    if (value && !context.animationPropertyKeywordAllowed())
4706                        return false;
4707                    if (currValue)
4708                        m_valueList->next();
4709                    break;
4710                case CSSPropertyWebkitAnimationTimingFunction:
4711                case CSSPropertyTransitionTimingFunction:
4712                case CSSPropertyWebkitTransitionTimingFunction:
4713                    currValue = parseAnimationTimingFunction();
4714                    if (currValue)
4715                        m_valueList->next();
4716                    break;
4717                default:
4718                    ASSERT_NOT_REACHED();
4719                    return false;
4720            }
4721
4722            if (!currValue)
4723                return false;
4724
4725            if (value && !values) {
4726                values = CSSValueList::createCommaSeparated();
4727                values->append(value.release());
4728            }
4729
4730            if (values)
4731                values->append(currValue.release());
4732            else
4733                value = currValue.release();
4734
4735            allowComma = true;
4736        }
4737
4738        // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
4739        // properties.
4740        if (inShorthand())
4741            break;
4742    }
4743
4744    if (values && values->length()) {
4745        result = values.release();
4746        return true;
4747    }
4748    if (value) {
4749        result = value.release();
4750        return true;
4751    }
4752    return false;
4753}
4754
4755bool CSSParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
4756{
4757    ShorthandScope scope(this, shorthandId);
4758    const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
4759    ASSERT(shorthand.length() == 2);
4760    if (!parseValue(shorthand.properties()[0], important))
4761        return false;
4762
4763    if (!m_valueList->current()) {
4764        // Only one value was specified, the opposite value should be set to 'auto'.
4765        // FIXME: If the first property was <ident>, the opposite value should be the same <ident>.
4766        addProperty(shorthand.properties()[1], cssValuePool().createIdentifierValue(CSSValueAuto), important);
4767        return true;
4768    }
4769
4770    if (!isForwardSlashOperator(m_valueList->current()))
4771        return false;
4772
4773    if (!m_valueList->next())
4774        return false;
4775
4776    return parseValue(shorthand.properties()[1], important);
4777}
4778
4779bool CSSParser::parseGridTrackList(CSSPropertyID propId, bool important)
4780{
4781    CSSParserValue* value = m_valueList->current();
4782    if (value->id == CSSValueNone) {
4783        if (m_valueList->next())
4784            return false;
4785
4786        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
4787        return true;
4788    }
4789
4790    RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
4791    while (m_valueList->current()) {
4792        RefPtr<CSSPrimitiveValue> primitiveValue = parseGridTrackSize();
4793        if (!primitiveValue)
4794            return false;
4795
4796        values->append(primitiveValue.release());
4797    }
4798    addProperty(propId, values.release(), important);
4799    return true;
4800}
4801
4802PassRefPtr<CSSPrimitiveValue> CSSParser::parseGridTrackSize()
4803{
4804    CSSParserValue* currentValue = m_valueList->current();
4805    m_valueList->next();
4806
4807    if (currentValue->id == CSSValueAuto)
4808        return cssValuePool().createIdentifierValue(CSSValueAuto);
4809
4810    if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax(")) {
4811        // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
4812        CSSParserValueList* arguments = currentValue->function->args.get();
4813        if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
4814            return 0;
4815
4816        RefPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0));
4817        if (!minTrackBreadth)
4818            return 0;
4819
4820        RefPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2));
4821        if (!maxTrackBreadth)
4822            return 0;
4823
4824        return createPrimitiveValuePair(minTrackBreadth, maxTrackBreadth);
4825    }
4826
4827    if (PassRefPtr<CSSPrimitiveValue> trackBreadth = parseGridBreadth(currentValue))
4828        return trackBreadth;
4829
4830    return 0;
4831}
4832
4833PassRefPtr<CSSPrimitiveValue> CSSParser::parseGridBreadth(CSSParserValue* currentValue)
4834{
4835    if (currentValue->id == CSSValueWebkitMinContent || currentValue->id == CSSValueWebkitMaxContent)
4836        return cssValuePool().createIdentifierValue(currentValue->id);
4837
4838    if (!validUnit(currentValue, FLength | FPercent))
4839        return 0;
4840
4841    return createPrimitiveNumericValue(currentValue);
4842}
4843
4844#if ENABLE(DASHBOARD_SUPPORT)
4845
4846#define DASHBOARD_REGION_NUM_PARAMETERS  6
4847#define DASHBOARD_REGION_SHORT_NUM_PARAMETERS  2
4848
4849static CSSParserValue* skipCommaInDashboardRegion(CSSParserValueList *args)
4850{
4851    if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) ||
4852         args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
4853        CSSParserValue* current = args->current();
4854        if (current->unit == CSSParserValue::Operator && current->iValue == ',')
4855            return args->next();
4856    }
4857    return args->current();
4858}
4859
4860bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important)
4861{
4862    bool valid = true;
4863
4864    CSSParserValue* value = m_valueList->current();
4865
4866    if (value->id == CSSValueNone) {
4867        if (m_valueList->next())
4868            return false;
4869        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
4870        return valid;
4871    }
4872
4873    RefPtr<DashboardRegion> firstRegion = DashboardRegion::create();
4874    DashboardRegion* region = 0;
4875
4876    while (value) {
4877        if (region == 0) {
4878            region = firstRegion.get();
4879        } else {
4880            RefPtr<DashboardRegion> nextRegion = DashboardRegion::create();
4881            region->m_next = nextRegion;
4882            region = nextRegion.get();
4883        }
4884
4885        if (value->unit != CSSParserValue::Function) {
4886            valid = false;
4887            break;
4888        }
4889
4890        // Commas count as values, so allow (function name is dashboard-region for DASHBOARD_SUPPORT feature):
4891        // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
4892        // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
4893        // also allow
4894        // dashboard-region(label, type) or dashboard-region(label type)
4895        // dashboard-region(label, type) or dashboard-region(label type)
4896        CSSParserValueList* args = value->function->args.get();
4897        if (!equalIgnoringCase(value->function->name, "dashboard-region(") || !args) {
4898            valid = false;
4899            break;
4900        }
4901
4902        int numArgs = args->size();
4903        if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) &&
4904            (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))) {
4905            valid = false;
4906            break;
4907        }
4908
4909        // First arg is a label.
4910        CSSParserValue* arg = args->current();
4911        if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
4912            valid = false;
4913            break;
4914        }
4915
4916        region->m_label = arg->string;
4917
4918        // Second arg is a type.
4919        arg = args->next();
4920        arg = skipCommaInDashboardRegion(args);
4921        if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
4922            valid = false;
4923            break;
4924        }
4925
4926        if (equalIgnoringCase(arg, "circle"))
4927            region->m_isCircle = true;
4928        else if (equalIgnoringCase(arg, "rectangle"))
4929            region->m_isRectangle = true;
4930        else {
4931            valid = false;
4932            break;
4933        }
4934
4935        region->m_geometryType = arg->string;
4936
4937        if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
4938            // This originally used CSSValueInvalid by accident. It might be more logical to use something else.
4939            RefPtr<CSSPrimitiveValue> amount = cssValuePool().createIdentifierValue(CSSValueInvalid);
4940
4941            region->setTop(amount);
4942            region->setRight(amount);
4943            region->setBottom(amount);
4944            region->setLeft(amount);
4945        } else {
4946            // Next four arguments must be offset numbers
4947            int i;
4948            for (i = 0; i < 4; i++) {
4949                arg = args->next();
4950                arg = skipCommaInDashboardRegion(args);
4951
4952                valid = arg->id == CSSValueAuto || validUnit(arg, FLength);
4953                if (!valid)
4954                    break;
4955
4956                RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ?
4957                    cssValuePool().createIdentifierValue(CSSValueAuto) :
4958                    createPrimitiveNumericValue(arg);
4959
4960                if (i == 0)
4961                    region->setTop(amount);
4962                else if (i == 1)
4963                    region->setRight(amount);
4964                else if (i == 2)
4965                    region->setBottom(amount);
4966                else
4967                    region->setLeft(amount);
4968            }
4969        }
4970
4971        if (args->next())
4972            return false;
4973
4974        value = m_valueList->next();
4975    }
4976
4977    if (valid)
4978        addProperty(propId, cssValuePool().createValue(firstRegion.release()), important);
4979
4980    return valid;
4981}
4982
4983#endif /* ENABLE(DASHBOARD_SUPPORT) */
4984
4985PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
4986{
4987    unsigned numArgs = args->size();
4988    if (counters && numArgs != 3 && numArgs != 5)
4989        return 0;
4990    if (!counters && numArgs != 1 && numArgs != 3)
4991        return 0;
4992
4993    CSSParserValue* i = args->current();
4994    if (i->unit != CSSPrimitiveValue::CSS_IDENT)
4995        return 0;
4996    RefPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i);
4997
4998    RefPtr<CSSPrimitiveValue> separator;
4999    if (!counters)
5000        separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING);
5001    else {
5002        i = args->next();
5003        if (i->unit != CSSParserValue::Operator || i->iValue != ',')
5004            return 0;
5005
5006        i = args->next();
5007        if (i->unit != CSSPrimitiveValue::CSS_STRING)
5008            return 0;
5009
5010        separator = createPrimitiveStringValue(i);
5011    }
5012
5013    RefPtr<CSSPrimitiveValue> listStyle;
5014    i = args->next();
5015    if (!i) // Make the list style default decimal
5016        listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
5017    else {
5018        if (i->unit != CSSParserValue::Operator || i->iValue != ',')
5019            return 0;
5020
5021        i = args->next();
5022        if (i->unit != CSSPrimitiveValue::CSS_IDENT)
5023            return 0;
5024
5025        int listStyleID = 0;
5026        if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha))
5027            listStyleID = i->id;
5028        else
5029            return 0;
5030
5031        listStyle = cssValuePool().createIdentifierValue(listStyleID);
5032    }
5033
5034    return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
5035}
5036
5037bool CSSParser::parseClipShape(CSSPropertyID propId, bool important)
5038{
5039    CSSParserValue* value = m_valueList->current();
5040    CSSParserValueList* args = value->function->args.get();
5041
5042    if (!equalIgnoringCase(value->function->name, "rect(") || !args)
5043        return false;
5044
5045    // rect(t, r, b, l) || rect(t r b l)
5046    if (args->size() != 4 && args->size() != 7)
5047        return false;
5048    RefPtr<Rect> rect = Rect::create();
5049    bool valid = true;
5050    int i = 0;
5051    CSSParserValue* a = args->current();
5052    while (a) {
5053        valid = a->id == CSSValueAuto || validUnit(a, FLength);
5054        if (!valid)
5055            break;
5056        RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
5057            cssValuePool().createIdentifierValue(CSSValueAuto) :
5058            createPrimitiveNumericValue(a);
5059        if (i == 0)
5060            rect->setTop(length);
5061        else if (i == 1)
5062            rect->setRight(length);
5063        else if (i == 2)
5064            rect->setBottom(length);
5065        else
5066            rect->setLeft(length);
5067        a = args->next();
5068        if (a && args->size() == 7) {
5069            if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
5070                a = args->next();
5071            } else {
5072                valid = false;
5073                break;
5074            }
5075        }
5076        i++;
5077    }
5078    if (valid) {
5079        addProperty(propId, cssValuePool().createValue(rect.release()), important);
5080        m_valueList->next();
5081        return true;
5082    }
5083    return false;
5084}
5085
5086PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeRectangle(CSSParserValueList* args)
5087{
5088    ASSERT(args);
5089
5090    // rect(x, y, width, height, [[rx], ry])
5091    if (args->size() != 7 && args->size() != 9 && args->size() != 11)
5092        return 0;
5093
5094    RefPtr<CSSBasicShapeRectangle> shape = CSSBasicShapeRectangle::create();
5095
5096    unsigned argumentNumber = 0;
5097    CSSParserValue* argument = args->current();
5098    while (argument) {
5099        Units unitFlags = FLength | FPercent;
5100        if (argumentNumber > 1) {
5101            // Arguments width, height, rx, and ry cannot be negative.
5102            unitFlags = unitFlags | FNonNeg;
5103        }
5104        if (!validUnit(argument, unitFlags))
5105            return 0;
5106
5107        RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5108        ASSERT(argumentNumber < 6);
5109        switch (argumentNumber) {
5110        case 0:
5111            shape->setX(length);
5112            break;
5113        case 1:
5114            shape->setY(length);
5115            break;
5116        case 2:
5117            shape->setWidth(length);
5118            break;
5119        case 3:
5120            shape->setHeight(length);
5121            break;
5122        case 4:
5123            shape->setRadiusX(length);
5124            break;
5125        case 5:
5126            shape->setRadiusY(length);
5127            break;
5128        }
5129        argument = args->next();
5130        if (argument) {
5131            if (!isComma(argument))
5132                return 0;
5133
5134            argument = args->next();
5135        }
5136        argumentNumber++;
5137    }
5138
5139    if (argumentNumber < 4)
5140        return 0;
5141    return shape;
5142}
5143
5144PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeInsetRectangle(CSSParserValueList* args)
5145{
5146    ASSERT(args);
5147
5148    // inset-rectangle(top, right, bottom, left, [[rx], ry])
5149    if (args->size() != 7 && args->size() != 9 && args->size() != 11)
5150        return 0;
5151
5152    RefPtr<CSSBasicShapeInsetRectangle> shape = CSSBasicShapeInsetRectangle::create();
5153
5154    unsigned argumentNumber = 0;
5155    CSSParserValue* argument = args->current();
5156    while (argument) {
5157        Units unitFlags = FLength | FPercent | FNonNeg;
5158        if (!validUnit(argument, unitFlags))
5159            return 0;
5160
5161        RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5162        ASSERT(argumentNumber < 6);
5163        switch (argumentNumber) {
5164        case 0:
5165            shape->setTop(length);
5166            break;
5167        case 1:
5168            shape->setRight(length);
5169            break;
5170        case 2:
5171            shape->setBottom(length);
5172            break;
5173        case 3:
5174            shape->setLeft(length);
5175            break;
5176        case 4:
5177            shape->setRadiusX(length);
5178            break;
5179        case 5:
5180            shape->setRadiusY(length);
5181            break;
5182        }
5183        argument = args->next();
5184        if (argument) {
5185            if (!isComma(argument))
5186                return 0;
5187
5188            argument = args->next();
5189        }
5190        argumentNumber++;
5191    }
5192
5193    if (argumentNumber < 4)
5194        return 0;
5195    return shape;
5196}
5197
5198PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeCircle(CSSParserValueList* args)
5199{
5200    ASSERT(args);
5201
5202    // circle(centerX, centerY, radius)
5203    if (args->size() != 5)
5204        return 0;
5205
5206    RefPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
5207
5208    unsigned argumentNumber = 0;
5209    CSSParserValue* argument = args->current();
5210    while (argument) {
5211        Units unitFlags = FLength | FPercent;
5212        if (argumentNumber == 2) {
5213            // Argument radius cannot be negative.
5214            unitFlags = unitFlags | FNonNeg;
5215        }
5216
5217        if (!validUnit(argument, unitFlags))
5218            return 0;
5219
5220        RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5221        ASSERT(argumentNumber < 3);
5222        switch (argumentNumber) {
5223        case 0:
5224            shape->setCenterX(length);
5225            break;
5226        case 1:
5227            shape->setCenterY(length);
5228            break;
5229        case 2:
5230            shape->setRadius(length);
5231            break;
5232        }
5233
5234        argument = args->next();
5235        if (argument) {
5236            if (!isComma(argument))
5237                return 0;
5238            argument = args->next();
5239        }
5240        argumentNumber++;
5241    }
5242
5243    if (argumentNumber < 3)
5244        return 0;
5245    return shape;
5246}
5247
5248PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeEllipse(CSSParserValueList* args)
5249{
5250    ASSERT(args);
5251
5252    // ellipse(centerX, centerY, radiusX, radiusY)
5253    if (args->size() != 7)
5254        return 0;
5255
5256    RefPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
5257    unsigned argumentNumber = 0;
5258    CSSParserValue* argument = args->current();
5259    while (argument) {
5260        Units unitFlags = FLength | FPercent;
5261        if (argumentNumber > 1) {
5262            // Arguments radiusX and radiusY cannot be negative.
5263            unitFlags = unitFlags | FNonNeg;
5264        }
5265        if (!validUnit(argument, unitFlags))
5266            return 0;
5267
5268        RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
5269        ASSERT(argumentNumber < 4);
5270        switch (argumentNumber) {
5271        case 0:
5272            shape->setCenterX(length);
5273            break;
5274        case 1:
5275            shape->setCenterY(length);
5276            break;
5277        case 2:
5278            shape->setRadiusX(length);
5279            break;
5280        case 3:
5281            shape->setRadiusY(length);
5282            break;
5283        }
5284
5285        argument = args->next();
5286        if (argument) {
5287            if (!isComma(argument))
5288                return 0;
5289            argument = args->next();
5290        }
5291        argumentNumber++;
5292    }
5293
5294    if (argumentNumber < 4)
5295        return 0;
5296    return shape;
5297}
5298
5299PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapePolygon(CSSParserValueList* args)
5300{
5301    ASSERT(args);
5302
5303    unsigned size = args->size();
5304    if (!size)
5305        return 0;
5306
5307    RefPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
5308
5309    CSSParserValue* argument = args->current();
5310    if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
5311        shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
5312
5313        if (!isComma(args->next()))
5314            return 0;
5315
5316        argument = args->next();
5317        size -= 2;
5318    }
5319
5320    // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one
5321    if (!size || (size % 3) - 2)
5322        return 0;
5323
5324    CSSParserValue* argumentX = argument;
5325    while (argumentX) {
5326        if (!validUnit(argumentX, FLength | FPercent))
5327            return 0;
5328
5329        CSSParserValue* argumentY = args->next();
5330        if (!argumentY || !validUnit(argumentY, FLength | FPercent))
5331            return 0;
5332
5333        RefPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX);
5334        RefPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY);
5335
5336        shape->appendPoint(xLength.release(), yLength.release());
5337
5338        CSSParserValue* commaOrNull = args->next();
5339        if (!commaOrNull)
5340            argumentX = 0;
5341        else if (!isComma(commaOrNull))
5342            return 0;
5343        else
5344            argumentX = args->next();
5345    }
5346
5347    return shape;
5348}
5349
5350bool CSSParser::parseBasicShape(CSSPropertyID propId, bool important)
5351{
5352    CSSParserValue* value = m_valueList->current();
5353    ASSERT(value->unit == CSSParserValue::Function);
5354    CSSParserValueList* args = value->function->args.get();
5355
5356    if (!args)
5357        return false;
5358
5359    RefPtr<CSSBasicShape> shape;
5360    if (equalIgnoringCase(value->function->name, "rectangle("))
5361        shape = parseBasicShapeRectangle(args);
5362    else if (equalIgnoringCase(value->function->name, "circle("))
5363        shape = parseBasicShapeCircle(args);
5364    else if (equalIgnoringCase(value->function->name, "ellipse("))
5365        shape = parseBasicShapeEllipse(args);
5366    else if (equalIgnoringCase(value->function->name, "polygon("))
5367        shape = parseBasicShapePolygon(args);
5368    else if (equalIgnoringCase(value->function->name, "inset-rectangle("))
5369        shape = parseBasicShapeInsetRectangle(args);
5370
5371    if (!shape)
5372        return false;
5373
5374    addProperty(propId, cssValuePool().createValue(shape.release()), important);
5375    m_valueList->next();
5376    return true;
5377}
5378
5379// [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
5380bool CSSParser::parseFont(bool important)
5381{
5382    // Let's check if there is an inherit or initial somewhere in the shorthand.
5383    for (unsigned i = 0; i < m_valueList->size(); ++i) {
5384        if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial)
5385            return false;
5386    }
5387
5388    ShorthandScope scope(this, CSSPropertyFont);
5389    // Optional font-style, font-variant and font-weight.
5390    bool fontStyleParsed = false;
5391    bool fontVariantParsed = false;
5392    bool fontWeightParsed = false;
5393    CSSParserValue* value;
5394    while ((value = m_valueList->current())) {
5395        if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
5396            addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
5397            fontStyleParsed = true;
5398        } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
5399            // Font variant in the shorthand is particular, it only accepts normal or small-caps.
5400            addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important);
5401            fontVariantParsed = true;
5402        } else if (!fontWeightParsed && parseFontWeight(important))
5403            fontWeightParsed = true;
5404        else
5405            break;
5406        m_valueList->next();
5407    }
5408
5409    if (!value)
5410        return false;
5411
5412    if (!fontStyleParsed)
5413        addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5414    if (!fontVariantParsed)
5415        addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5416    if (!fontWeightParsed)
5417        addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5418
5419    // Now a font size _must_ come.
5420    // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
5421    if (!parseFontSize(important))
5422        return false;
5423
5424    value = m_valueList->current();
5425    if (!value)
5426        return false;
5427
5428    if (isForwardSlashOperator(value)) {
5429        // The line-height property.
5430        value = m_valueList->next();
5431        if (!value)
5432            return false;
5433        if (!parseLineHeight(important))
5434            return false;
5435    } else
5436        addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
5437
5438    // Font family must come now.
5439    RefPtr<CSSValue> parsedFamilyValue = parseFontFamily();
5440    if (!parsedFamilyValue)
5441        return false;
5442
5443    addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
5444
5445    // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
5446    // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
5447    // but we don't seem to support them at the moment. They should also be added here once implemented.
5448    if (m_valueList->current())
5449        return false;
5450
5451    return true;
5452}
5453
5454class FontFamilyValueBuilder {
5455public:
5456    FontFamilyValueBuilder(CSSValueList* list)
5457        : m_list(list)
5458    {
5459    }
5460
5461    void add(const CSSParserString& string)
5462    {
5463        if (!m_builder.isEmpty())
5464            m_builder.append(' ');
5465
5466        if (string.is8Bit()) {
5467            m_builder.append(string.characters8(), string.length());
5468            return;
5469        }
5470
5471        m_builder.append(string.characters16(), string.length());
5472    }
5473
5474    void commit()
5475    {
5476        if (m_builder.isEmpty())
5477            return;
5478        m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString()));
5479        m_builder.clear();
5480    }
5481
5482private:
5483    StringBuilder m_builder;
5484    CSSValueList* m_list;
5485};
5486
5487PassRefPtr<CSSValueList> CSSParser::parseFontFamily()
5488{
5489    RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
5490    CSSParserValue* value = m_valueList->current();
5491
5492    FontFamilyValueBuilder familyBuilder(list.get());
5493    bool inFamily = false;
5494
5495    while (value) {
5496        CSSParserValue* nextValue = m_valueList->next();
5497        bool nextValBreaksFont = !nextValue ||
5498                                 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
5499        bool nextValIsFontName = nextValue &&
5500            ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
5501            (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
5502
5503        bool valueIsKeyword = value->id == CSSValueInitial || value->id == CSSValueInherit || value->id == CSSValueDefault;
5504        if (valueIsKeyword && !inFamily) {
5505            if (nextValBreaksFont)
5506                value = m_valueList->next();
5507            else if (nextValIsFontName)
5508                value = nextValue;
5509            continue;
5510        }
5511
5512        if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
5513            if (inFamily)
5514                familyBuilder.add(value->string);
5515            else if (nextValBreaksFont || !nextValIsFontName)
5516                list->append(cssValuePool().createIdentifierValue(value->id));
5517            else {
5518                familyBuilder.commit();
5519                familyBuilder.add(value->string);
5520                inFamily = true;
5521            }
5522        } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
5523            // Strings never share in a family name.
5524            inFamily = false;
5525            familyBuilder.commit();
5526            list->append(cssValuePool().createFontFamilyValue(value->string));
5527        } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
5528            if (inFamily)
5529                familyBuilder.add(value->string);
5530            else if (nextValBreaksFont || !nextValIsFontName)
5531                list->append(cssValuePool().createFontFamilyValue(value->string));
5532            else {
5533                familyBuilder.commit();
5534                familyBuilder.add(value->string);
5535                inFamily = true;
5536            }
5537        } else {
5538            break;
5539        }
5540
5541        if (!nextValue)
5542            break;
5543
5544        if (nextValBreaksFont) {
5545            value = m_valueList->next();
5546            familyBuilder.commit();
5547            inFamily = false;
5548        }
5549        else if (nextValIsFontName)
5550            value = nextValue;
5551        else
5552            break;
5553    }
5554    familyBuilder.commit();
5555
5556    if (!list->length())
5557        list = 0;
5558    return list.release();
5559}
5560
5561bool CSSParser::parseLineHeight(bool important)
5562{
5563    CSSParserValue* value = m_valueList->current();
5564    int id = value->id;
5565    bool validPrimitive = false;
5566    // normal | <number> | <length> | <percentage> | inherit
5567    if (id == CSSValueNormal)
5568        validPrimitive = true;
5569    else
5570        validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
5571    if (validPrimitive && (!m_valueList->next() || inShorthand()))
5572        addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important);
5573    return validPrimitive;
5574}
5575
5576bool CSSParser::parseFontSize(bool important)
5577{
5578    CSSParserValue* value = m_valueList->current();
5579    int id = value->id;
5580    bool validPrimitive = false;
5581    // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
5582    if (id >= CSSValueXxSmall && id <= CSSValueLarger)
5583        validPrimitive = true;
5584    else
5585        validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
5586    if (validPrimitive && (!m_valueList->next() || inShorthand()))
5587        addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important);
5588    return validPrimitive;
5589}
5590
5591bool CSSParser::parseFontVariant(bool important)
5592{
5593    RefPtr<CSSValueList> values;
5594    if (m_valueList->size() > 1)
5595        values = CSSValueList::createCommaSeparated();
5596    CSSParserValue* val;
5597    bool expectComma = false;
5598    while ((val = m_valueList->current())) {
5599        RefPtr<CSSPrimitiveValue> parsedValue;
5600        if (!expectComma) {
5601            expectComma = true;
5602            if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
5603                parsedValue = cssValuePool().createIdentifierValue(val->id);
5604            else if (val->id == CSSValueAll && !values) {
5605                // 'all' is only allowed in @font-face and with no other values. Make a value list to
5606                // indicate that we are in the @font-face case.
5607                values = CSSValueList::createCommaSeparated();
5608                parsedValue = cssValuePool().createIdentifierValue(val->id);
5609            }
5610        } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
5611            expectComma = false;
5612            m_valueList->next();
5613            continue;
5614        }
5615
5616        if (!parsedValue)
5617            return false;
5618
5619        m_valueList->next();
5620
5621        if (values)
5622            values->append(parsedValue.release());
5623        else {
5624            addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
5625            return true;
5626        }
5627    }
5628
5629    if (values && values->length()) {
5630        m_hasFontFaceOnlyValues = true;
5631        addProperty(CSSPropertyFontVariant, values.release(), important);
5632        return true;
5633    }
5634
5635    return false;
5636}
5637
5638bool CSSParser::parseFontWeight(bool important)
5639{
5640    CSSParserValue* value = m_valueList->current();
5641    if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
5642        addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important);
5643        return true;
5644    }
5645    if (validUnit(value, FInteger | FNonNeg, CSSQuirksMode)) {
5646        int weight = static_cast<int>(value->fValue);
5647        if (!(weight % 100) && weight >= 100 && weight <= 900) {
5648            addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValue100 + weight / 100 - 1), important);
5649            return true;
5650        }
5651    }
5652    return false;
5653}
5654
5655bool CSSParser::parseFontFaceSrcURI(CSSValueList* valueList)
5656{
5657    RefPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string)));
5658
5659    CSSParserValue* value = m_valueList->next();
5660    if (!value) {
5661        valueList->append(uriValue.release());
5662        return true;
5663    }
5664    if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
5665        m_valueList->next();
5666        valueList->append(uriValue.release());
5667        return true;
5668    }
5669
5670    if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format("))
5671        return false;
5672
5673    // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
5674    // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
5675    CSSParserValueList* args = value->function->args.get();
5676    if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
5677        return false;
5678    uriValue->setFormat(args->current()->string);
5679    valueList->append(uriValue.release());
5680    value = m_valueList->next();
5681    if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
5682        m_valueList->next();
5683    return true;
5684}
5685
5686bool CSSParser::parseFontFaceSrcLocal(CSSValueList* valueList)
5687{
5688    CSSParserValueList* args = m_valueList->current()->function->args.get();
5689    if (!args || !args->size())
5690        return false;
5691
5692    if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING)
5693        valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string));
5694    else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
5695        StringBuilder builder;
5696        for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) {
5697            if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
5698                return false;
5699            if (!builder.isEmpty())
5700                builder.append(' ');
5701            builder.append(localValue->string);
5702        }
5703        valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
5704    } else
5705        return false;
5706
5707    if (CSSParserValue* value = m_valueList->next()) {
5708        if (value->unit == CSSParserValue::Operator && value->iValue == ',')
5709            m_valueList->next();
5710    }
5711    return true;
5712}
5713
5714bool CSSParser::parseFontFaceSrc()
5715{
5716    RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
5717
5718    while (CSSParserValue* value = m_valueList->current()) {
5719        if (value->unit == CSSPrimitiveValue::CSS_URI) {
5720            if (!parseFontFaceSrcURI(values.get()))
5721                return false;
5722        } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) {
5723            if (!parseFontFaceSrcLocal(values.get()))
5724                return false;
5725        } else
5726            return false;
5727    }
5728    if (!values->length())
5729        return false;
5730
5731    addProperty(CSSPropertySrc, values.release(), m_important);
5732    m_valueList->next();
5733    return true;
5734}
5735
5736bool CSSParser::parseFontFaceUnicodeRange()
5737{
5738    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
5739    bool failed = false;
5740    bool operatorExpected = false;
5741    for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
5742        if (operatorExpected) {
5743            if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
5744                continue;
5745            failed = true;
5746            break;
5747        }
5748        if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
5749            failed = true;
5750            break;
5751        }
5752
5753        String rangeString = m_valueList->current()->string;
5754        UChar32 from = 0;
5755        UChar32 to = 0;
5756        unsigned length = rangeString.length();
5757
5758        if (length < 3) {
5759            failed = true;
5760            break;
5761        }
5762
5763        unsigned i = 2;
5764        while (i < length) {
5765            UChar c = rangeString[i];
5766            if (c == '-' || c == '?')
5767                break;
5768            from *= 16;
5769            if (c >= '0' && c <= '9')
5770                from += c - '0';
5771            else if (c >= 'A' && c <= 'F')
5772                from += 10 + c - 'A';
5773            else if (c >= 'a' && c <= 'f')
5774                from += 10 + c - 'a';
5775            else {
5776                failed = true;
5777                break;
5778            }
5779            i++;
5780        }
5781        if (failed)
5782            break;
5783
5784        if (i == length)
5785            to = from;
5786        else if (rangeString[i] == '?') {
5787            unsigned span = 1;
5788            while (i < length && rangeString[i] == '?') {
5789                span *= 16;
5790                from *= 16;
5791                i++;
5792            }
5793            if (i < length)
5794                failed = true;
5795            to = from + span - 1;
5796        } else {
5797            if (length < i + 2) {
5798                failed = true;
5799                break;
5800            }
5801            i++;
5802            while (i < length) {
5803                UChar c = rangeString[i];
5804                to *= 16;
5805                if (c >= '0' && c <= '9')
5806                    to += c - '0';
5807                else if (c >= 'A' && c <= 'F')
5808                    to += 10 + c - 'A';
5809                else if (c >= 'a' && c <= 'f')
5810                    to += 10 + c - 'a';
5811                else {
5812                    failed = true;
5813                    break;
5814                }
5815                i++;
5816            }
5817            if (failed)
5818                break;
5819        }
5820        if (from <= to)
5821            values->append(CSSUnicodeRangeValue::create(from, to));
5822    }
5823    if (failed || !values->length())
5824        return false;
5825    addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
5826    return true;
5827}
5828
5829// Returns the number of characters which form a valid double
5830// and are terminated by the given terminator character
5831template <typename CharacterType>
5832static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
5833{
5834    int length = end - string;
5835    if (length < 1)
5836        return 0;
5837
5838    bool decimalMarkSeen = false;
5839    int processedLength = 0;
5840
5841    for (int i = 0; i < length; ++i) {
5842        if (string[i] == terminator) {
5843            processedLength = i;
5844            break;
5845        }
5846        if (!isASCIIDigit(string[i])) {
5847            if (!decimalMarkSeen && string[i] == '.')
5848                decimalMarkSeen = true;
5849            else
5850                return 0;
5851        }
5852    }
5853
5854    if (decimalMarkSeen && processedLength == 1)
5855        return 0;
5856
5857    return processedLength;
5858}
5859
5860// Returns the number of characters consumed for parsing a valid double
5861// terminated by the given terminator character
5862template <typename CharacterType>
5863static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value)
5864{
5865    int length = checkForValidDouble(string, end, terminator);
5866    if (!length)
5867        return 0;
5868
5869    int position = 0;
5870    double localValue = 0;
5871
5872    // The consumed characters here are guaranteed to be
5873    // ASCII digits with or without a decimal mark
5874    for (; position < length; ++position) {
5875        if (string[position] == '.')
5876            break;
5877        localValue = localValue * 10 + string[position] - '0';
5878    }
5879
5880    if (++position == length) {
5881        value = localValue;
5882        return length;
5883    }
5884
5885    double fraction = 0;
5886    double scale = 1;
5887
5888    while (position < length && scale < MAX_SCALE) {
5889        fraction = fraction * 10 + string[position++] - '0';
5890        scale *= 10;
5891    }
5892
5893    value = localValue + fraction / scale;
5894    return length;
5895}
5896
5897template <typename CharacterType>
5898static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
5899{
5900    const CharacterType* current = string;
5901    double localValue = 0;
5902    bool negative = false;
5903    while (current != end && isHTMLSpace(*current))
5904        current++;
5905    if (current != end && *current == '-') {
5906        negative = true;
5907        current++;
5908    }
5909    if (current == end || !isASCIIDigit(*current))
5910        return false;
5911    while (current != end && isASCIIDigit(*current)) {
5912        double newValue = localValue * 10 + *current++ - '0';
5913        if (newValue >= 255) {
5914            // Clamp values at 255.
5915            localValue = 255;
5916            while (current != end && isASCIIDigit(*current))
5917                ++current;
5918            break;
5919        }
5920        localValue = newValue;
5921    }
5922
5923    if (current == end)
5924        return false;
5925
5926    if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
5927        return false;
5928
5929    if (*current == '.') {
5930        // We already parsed the integral part, try to parse
5931        // the fraction part of the percentage value.
5932        double percentage = 0;
5933        int numCharactersParsed = parseDouble(current, end, '%', percentage);
5934        if (!numCharactersParsed)
5935            return false;
5936        current += numCharactersParsed;
5937        if (*current != '%')
5938            return false;
5939        localValue += percentage;
5940    }
5941
5942    if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
5943        return false;
5944
5945    if (*current == '%') {
5946        expect = CSSPrimitiveValue::CSS_PERCENTAGE;
5947        localValue = localValue / 100.0 * 256.0;
5948        // Clamp values at 255 for percentages over 100%
5949        if (localValue > 255)
5950            localValue = 255;
5951        current++;
5952    } else
5953        expect = CSSPrimitiveValue::CSS_NUMBER;
5954
5955    while (current != end && isHTMLSpace(*current))
5956        current++;
5957    if (current == end || *current++ != terminator)
5958        return false;
5959    // Clamp negative values at zero.
5960    value = negative ? 0 : static_cast<int>(localValue);
5961    string = current;
5962    return true;
5963}
5964
5965template <typename CharacterType>
5966static inline bool isTenthAlpha(const CharacterType* string, const int length)
5967{
5968    // "0.X"
5969    if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
5970        return true;
5971
5972    // ".X"
5973    if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
5974        return true;
5975
5976    return false;
5977}
5978
5979template <typename CharacterType>
5980static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
5981{
5982    while (string != end && isHTMLSpace(*string))
5983        string++;
5984
5985    bool negative = false;
5986
5987    if (string != end && *string == '-') {
5988        negative = true;
5989        string++;
5990    }
5991
5992    value = 0;
5993
5994    int length = end - string;
5995    if (length < 2)
5996        return false;
5997
5998    if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
5999        return false;
6000
6001    if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
6002        if (checkForValidDouble(string, end, terminator)) {
6003            value = negative ? 0 : 255;
6004            string = end;
6005            return true;
6006        }
6007        return false;
6008    }
6009
6010    if (length == 2 && string[0] != '.') {
6011        value = !negative && string[0] == '1' ? 255 : 0;
6012        string = end;
6013        return true;
6014    }
6015
6016    if (isTenthAlpha(string, length - 1)) {
6017        static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
6018        value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
6019        string = end;
6020        return true;
6021    }
6022
6023    double alpha = 0;
6024    if (!parseDouble(string, end, terminator, alpha))
6025        return false;
6026    value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
6027    string = end;
6028    return true;
6029}
6030
6031template <typename CharacterType>
6032static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
6033{
6034    if (length < 5)
6035        return false;
6036    return characters[4] == '('
6037        && isASCIIAlphaCaselessEqual(characters[0], 'r')
6038        && isASCIIAlphaCaselessEqual(characters[1], 'g')
6039        && isASCIIAlphaCaselessEqual(characters[2], 'b')
6040        && isASCIIAlphaCaselessEqual(characters[3], 'a');
6041}
6042
6043template <typename CharacterType>
6044static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
6045{
6046    if (length < 4)
6047        return false;
6048    return characters[3] == '('
6049        && isASCIIAlphaCaselessEqual(characters[0], 'r')
6050        && isASCIIAlphaCaselessEqual(characters[1], 'g')
6051        && isASCIIAlphaCaselessEqual(characters[2], 'b');
6052}
6053
6054template <typename CharacterType>
6055static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length , bool strict)
6056{
6057    CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
6058
6059    if (!strict && length >= 3) {
6060        if (characters[0] == '#') {
6061            if (Color::parseHexColor(characters + 1, length - 1, rgb))
6062                return true;
6063        } else {
6064            if (Color::parseHexColor(characters, length, rgb))
6065                return true;
6066        }
6067    }
6068
6069    // Try rgba() syntax.
6070    if (mightBeRGBA(characters, length)) {
6071        const CharacterType* current = characters + 5;
6072        const CharacterType* end = characters + length;
6073        int red;
6074        int green;
6075        int blue;
6076        int alpha;
6077
6078        if (!parseColorIntOrPercentage(current, end, ',', expect, red))
6079            return false;
6080        if (!parseColorIntOrPercentage(current, end, ',', expect, green))
6081            return false;
6082        if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
6083            return false;
6084        if (!parseAlphaValue(current, end, ')', alpha))
6085            return false;
6086        if (current != end)
6087            return false;
6088        rgb = makeRGBA(red, green, blue, alpha);
6089        return true;
6090    }
6091
6092    // Try rgb() syntax.
6093    if (mightBeRGB(characters, length)) {
6094        const CharacterType* current = characters + 4;
6095        const CharacterType* end = characters + length;
6096        int red;
6097        int green;
6098        int blue;
6099        if (!parseColorIntOrPercentage(current, end, ',', expect, red))
6100            return false;
6101        if (!parseColorIntOrPercentage(current, end, ',', expect, green))
6102            return false;
6103        if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
6104            return false;
6105        if (current != end)
6106            return false;
6107        rgb = makeRGB(red, green, blue);
6108        return true;
6109    }
6110
6111    return false;
6112}
6113
6114template<typename StringType>
6115bool CSSParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict)
6116{
6117    unsigned length = name.length();
6118    bool parseResult;
6119
6120    if (!length)
6121        return false;
6122
6123    if (name.is8Bit())
6124        parseResult = fastParseColorInternal(rgb, name.characters8(), length, strict);
6125    else
6126        parseResult = fastParseColorInternal(rgb, name.characters16(), length, strict);
6127
6128    if (parseResult)
6129        return true;
6130
6131    // Try named colors.
6132    Color tc;
6133    tc.setNamedColor(name);
6134    if (tc.isValid()) {
6135        rgb = tc.rgb();
6136        return true;
6137    }
6138    return false;
6139}
6140
6141inline double CSSParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc)
6142{
6143    const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue;
6144    if (releaseCalc == ReleaseParsedCalcValue)
6145        m_parsedCalculation.release();
6146    return result;
6147}
6148
6149bool CSSParser::isCalculation(CSSParserValue* value)
6150{
6151    return (value->unit == CSSParserValue::Function)
6152        && (equalIgnoringCase(value->function->name, "calc(")
6153            || equalIgnoringCase(value->function->name, "-webkit-calc(")
6154            || equalIgnoringCase(value->function->name, "-webkit-min(")
6155            || equalIgnoringCase(value->function->name, "-webkit-max("));
6156}
6157
6158inline int CSSParser::colorIntFromValue(CSSParserValue* v)
6159{
6160    bool isPercent;
6161
6162    if (m_parsedCalculation)
6163        isPercent = m_parsedCalculation->category() == CalcPercent;
6164    else
6165        isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
6166
6167    const double value = parsedDouble(v, ReleaseParsedCalcValue);
6168
6169    if (value <= 0.0)
6170        return 0;
6171
6172    if (isPercent) {
6173        if (value >= 100.0)
6174            return 255;
6175        return static_cast<int>(value * 256.0 / 100.0);
6176    }
6177
6178    if (value >= 255.0)
6179        return 255;
6180
6181    return static_cast<int>(value);
6182}
6183
6184bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
6185{
6186    CSSParserValueList* args = value->function->args.get();
6187    CSSParserValue* v = args->current();
6188    Units unitType = FUnknown;
6189    // Get the first value and its type
6190    if (validUnit(v, FInteger, CSSStrictMode))
6191        unitType = FInteger;
6192    else if (validUnit(v, FPercent, CSSStrictMode))
6193        unitType = FPercent;
6194    else
6195        return false;
6196
6197    colorArray[0] = colorIntFromValue(v);
6198    for (int i = 1; i < 3; i++) {
6199        v = args->next();
6200        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6201            return false;
6202        v = args->next();
6203        if (!validUnit(v, unitType, CSSStrictMode))
6204            return false;
6205        colorArray[i] = colorIntFromValue(v);
6206    }
6207    if (parseAlpha) {
6208        v = args->next();
6209        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6210            return false;
6211        v = args->next();
6212        if (!validUnit(v, FNumber, CSSStrictMode))
6213            return false;
6214        const double value = parsedDouble(v, ReleaseParsedCalcValue);
6215        // Convert the floating pointer number of alpha to an integer in the range [0, 256),
6216        // with an equal distribution across all 256 values.
6217        colorArray[3] = static_cast<int>(max(0.0, min(1.0, value)) * nextafter(256.0, 0.0));
6218    }
6219    return true;
6220}
6221
6222// The CSS3 specification defines the format of a HSL color as
6223// hsl(<number>, <percent>, <percent>)
6224// and with alpha, the format is
6225// hsla(<number>, <percent>, <percent>, <number>)
6226// The first value, HUE, is in an angle with a value between 0 and 360
6227bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
6228{
6229    CSSParserValueList* args = value->function->args.get();
6230    CSSParserValue* v = args->current();
6231    // Get the first value
6232    if (!validUnit(v, FNumber, CSSStrictMode))
6233        return false;
6234    // normalize the Hue value and change it to be between 0 and 1.0
6235    colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0;
6236    for (int i = 1; i < 3; i++) {
6237        v = args->next();
6238        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6239            return false;
6240        v = args->next();
6241        if (!validUnit(v, FPercent, CSSStrictMode))
6242            return false;
6243        colorArray[i] = max(0.0, min(100.0, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0
6244    }
6245    if (parseAlpha) {
6246        v = args->next();
6247        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6248            return false;
6249        v = args->next();
6250        if (!validUnit(v, FNumber, CSSStrictMode))
6251            return false;
6252        colorArray[3] = max(0.0, min(1.0, parsedDouble(v, ReleaseParsedCalcValue)));
6253    }
6254    return true;
6255}
6256
6257PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value)
6258{
6259    RGBA32 c = Color::transparent;
6260    if (!parseColorFromValue(value ? value : m_valueList->current(), c))
6261        return 0;
6262    return cssValuePool().createColorValue(c);
6263}
6264
6265bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
6266{
6267    if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
6268        && value->fValue >= 0. && value->fValue < 1000000.) {
6269        String str = String::format("%06d", static_cast<int>((value->fValue+.5)));
6270        // FIXME: This should be strict parsing for SVG as well.
6271        if (!fastParseColor(c, str, inStrictMode()))
6272            return false;
6273    } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
6274                value->unit == CSSPrimitiveValue::CSS_IDENT ||
6275                (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
6276        if (!fastParseColor(c, value->string, inStrictMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
6277            return false;
6278    } else if (value->unit == CSSParserValue::Function &&
6279                value->function->args != 0 &&
6280                value->function->args->size() == 5 /* rgb + two commas */ &&
6281                equalIgnoringCase(value->function->name, "rgb(")) {
6282        int colorValues[3];
6283        if (!parseColorParameters(value, colorValues, false))
6284            return false;
6285        c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
6286    } else {
6287        if (value->unit == CSSParserValue::Function &&
6288                value->function->args != 0 &&
6289                value->function->args->size() == 7 /* rgba + three commas */ &&
6290                equalIgnoringCase(value->function->name, "rgba(")) {
6291            int colorValues[4];
6292            if (!parseColorParameters(value, colorValues, true))
6293                return false;
6294            c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
6295        } else if (value->unit == CSSParserValue::Function &&
6296                    value->function->args != 0 &&
6297                    value->function->args->size() == 5 /* hsl + two commas */ &&
6298                    equalIgnoringCase(value->function->name, "hsl(")) {
6299            double colorValues[3];
6300            if (!parseHSLParameters(value, colorValues, false))
6301                return false;
6302            c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
6303        } else if (value->unit == CSSParserValue::Function &&
6304                    value->function->args != 0 &&
6305                    value->function->args->size() == 7 /* hsla + three commas */ &&
6306                    equalIgnoringCase(value->function->name, "hsla(")) {
6307            double colorValues[4];
6308            if (!parseHSLParameters(value, colorValues, true))
6309                return false;
6310            c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
6311        } else
6312            return false;
6313    }
6314
6315    return true;
6316}
6317
6318// This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
6319// without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
6320struct ShadowParseContext {
6321    ShadowParseContext(CSSPropertyID prop, CSSParser* parser)
6322        : property(prop)
6323        , m_parser(parser)
6324        , allowX(true)
6325        , allowY(false)
6326        , allowBlur(false)
6327        , allowSpread(false)
6328        , allowColor(true)
6329        , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
6330        , allowBreak(true)
6331    {
6332    }
6333
6334    bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
6335
6336    void commitValue()
6337    {
6338        // Handle the ,, case gracefully by doing nothing.
6339        if (x || y || blur || spread || color || style) {
6340            if (!values)
6341                values = CSSValueList::createCommaSeparated();
6342
6343            // Construct the current shadow value and add it to the list.
6344            values->append(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
6345        }
6346
6347        // Now reset for the next shadow value.
6348        x = 0;
6349        y = 0;
6350        blur = 0;
6351        spread = 0;
6352        style = 0;
6353        color = 0;
6354
6355        allowX = true;
6356        allowColor = true;
6357        allowBreak = true;
6358        allowY = false;
6359        allowBlur = false;
6360        allowSpread = false;
6361        allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6362    }
6363
6364    void commitLength(CSSParserValue* v)
6365    {
6366        RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
6367
6368        if (allowX) {
6369            x = val.release();
6370            allowX = false;
6371            allowY = true;
6372            allowColor = false;
6373            allowStyle = false;
6374            allowBreak = false;
6375        } else if (allowY) {
6376            y = val.release();
6377            allowY = false;
6378            allowBlur = true;
6379            allowColor = true;
6380            allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6381            allowBreak = true;
6382        } else if (allowBlur) {
6383            blur = val.release();
6384            allowBlur = false;
6385            allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6386        } else if (allowSpread) {
6387            spread = val.release();
6388            allowSpread = false;
6389        }
6390    }
6391
6392    void commitColor(PassRefPtr<CSSPrimitiveValue> val)
6393    {
6394        color = val;
6395        allowColor = false;
6396        if (allowX) {
6397            allowStyle = false;
6398            allowBreak = false;
6399        } else {
6400            allowBlur = false;
6401            allowSpread = false;
6402            allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6403        }
6404    }
6405
6406    void commitStyle(CSSParserValue* v)
6407    {
6408        style = cssValuePool().createIdentifierValue(v->id);
6409        allowStyle = false;
6410        if (allowX)
6411            allowBreak = false;
6412        else {
6413            allowBlur = false;
6414            allowSpread = false;
6415            allowColor = false;
6416        }
6417    }
6418
6419    CSSPropertyID property;
6420    CSSParser* m_parser;
6421
6422    RefPtr<CSSValueList> values;
6423    RefPtr<CSSPrimitiveValue> x;
6424    RefPtr<CSSPrimitiveValue> y;
6425    RefPtr<CSSPrimitiveValue> blur;
6426    RefPtr<CSSPrimitiveValue> spread;
6427    RefPtr<CSSPrimitiveValue> style;
6428    RefPtr<CSSPrimitiveValue> color;
6429
6430    bool allowX;
6431    bool allowY;
6432    bool allowBlur;
6433    bool allowSpread;
6434    bool allowColor;
6435    bool allowStyle; // inset or not.
6436    bool allowBreak;
6437};
6438
6439PassRefPtr<CSSValueList> CSSParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId)
6440{
6441    ShadowParseContext context(propId, this);
6442    CSSParserValue* val;
6443    while ((val = valueList->current())) {
6444        // Check for a comma break first.
6445        if (val->unit == CSSParserValue::Operator) {
6446            if (val->iValue != ',' || !context.allowBreak)
6447                // Other operators aren't legal or we aren't done with the current shadow
6448                // value.  Treat as invalid.
6449                return 0;
6450#if ENABLE(SVG)
6451            // -webkit-svg-shadow does not support multiple values.
6452            if (propId == CSSPropertyWebkitSvgShadow)
6453                return 0;
6454#endif
6455            // The value is good.  Commit it.
6456            context.commitValue();
6457        } else if (validUnit(val, FLength, CSSStrictMode)) {
6458            // We required a length and didn't get one. Invalid.
6459            if (!context.allowLength())
6460                return 0;
6461
6462            // Blur radius must be non-negative.
6463            if (context.allowBlur && !validUnit(val, FLength | FNonNeg, CSSStrictMode))
6464                return 0;
6465
6466            // A length is allowed here.  Construct the value and add it.
6467            context.commitLength(val);
6468        } else if (val->id == CSSValueInset) {
6469            if (!context.allowStyle)
6470                return 0;
6471
6472            context.commitStyle(val);
6473        } else {
6474            // The only other type of value that's ok is a color value.
6475            RefPtr<CSSPrimitiveValue> parsedColor;
6476            bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu
6477                            || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode())
6478                            || val->id == CSSValueCurrentcolor);
6479            if (isColor) {
6480                if (!context.allowColor)
6481                    return 0;
6482                parsedColor = cssValuePool().createIdentifierValue(val->id);
6483            }
6484
6485            if (!parsedColor)
6486                // It's not built-in. Try to parse it as a color.
6487                parsedColor = parseColor(val);
6488
6489            if (!parsedColor || !context.allowColor)
6490                return 0; // This value is not a color or length and is invalid or
6491                          // it is a color, but a color isn't allowed at this point.
6492
6493            context.commitColor(parsedColor.release());
6494        }
6495
6496        valueList->next();
6497    }
6498
6499    if (context.allowBreak) {
6500        context.commitValue();
6501        if (context.values && context.values->length())
6502            return context.values.release();
6503    }
6504
6505    return 0;
6506}
6507
6508bool CSSParser::parseReflect(CSSPropertyID propId, bool important)
6509{
6510    // box-reflect: <direction> <offset> <mask>
6511
6512    // Direction comes first.
6513    CSSParserValue* val = m_valueList->current();
6514    RefPtr<CSSPrimitiveValue> direction;
6515#if ENABLE(CSS_VARIABLES)
6516    if (val->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
6517        direction = createPrimitiveVariableNameValue(val);
6518    else
6519#endif
6520    switch (val->id) {
6521        case CSSValueAbove:
6522        case CSSValueBelow:
6523        case CSSValueLeft:
6524        case CSSValueRight:
6525            direction = cssValuePool().createIdentifierValue(val->id);
6526            break;
6527        default:
6528            return false;
6529    }
6530
6531    // The offset comes next.
6532    val = m_valueList->next();
6533    RefPtr<CSSPrimitiveValue> offset;
6534    if (!val)
6535        offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6536    else {
6537        if (!validUnit(val, FLength | FPercent))
6538            return false;
6539        offset = createPrimitiveNumericValue(val);
6540    }
6541
6542    // Now for the mask.
6543    RefPtr<CSSValue> mask;
6544    val = m_valueList->next();
6545    if (val) {
6546        if (!parseBorderImage(propId, mask))
6547            return false;
6548    }
6549
6550    RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction.release(), offset.release(), mask.release());
6551    addProperty(propId, reflectValue.release(), important);
6552    m_valueList->next();
6553    return true;
6554}
6555
6556bool CSSParser::parseFlex(CSSParserValueList* args, bool important)
6557{
6558    if (!args || !args->size() || args->size() > 3)
6559        return false;
6560    static const double unsetValue = -1;
6561    double flexGrow = unsetValue;
6562    double flexShrink = unsetValue;
6563    RefPtr<CSSPrimitiveValue> flexBasis;
6564
6565    while (CSSParserValue* arg = args->current()) {
6566        if (validUnit(arg, FNumber | FNonNeg)) {
6567            if (flexGrow == unsetValue)
6568                flexGrow = arg->fValue;
6569            else if (flexShrink == unsetValue)
6570                flexShrink = arg->fValue;
6571            else if (!arg->fValue) {
6572                // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
6573                flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6574            } else {
6575                // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
6576                return false;
6577            }
6578        } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg)))
6579            flexBasis = parseValidPrimitive(arg->id, arg);
6580        else {
6581            // Not a valid arg for flex.
6582            return false;
6583        }
6584        args->next();
6585    }
6586
6587    if (flexGrow == unsetValue)
6588        flexGrow = 1;
6589    if (flexShrink == unsetValue)
6590        flexShrink = 1;
6591    if (!flexBasis)
6592        flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6593
6594    addProperty(CSSPropertyWebkitFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
6595    addProperty(CSSPropertyWebkitFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
6596    addProperty(CSSPropertyWebkitFlexBasis, flexBasis, important);
6597    return true;
6598}
6599
6600struct BorderImageParseContext {
6601    BorderImageParseContext()
6602    : m_canAdvance(false)
6603    , m_allowCommit(true)
6604    , m_allowImage(true)
6605    , m_allowImageSlice(true)
6606    , m_allowRepeat(true)
6607    , m_allowForwardSlashOperator(false)
6608    , m_requireWidth(false)
6609    , m_requireOutset(false)
6610    {}
6611
6612    bool canAdvance() const { return m_canAdvance; }
6613    void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
6614
6615    bool allowCommit() const { return m_allowCommit; }
6616    bool allowImage() const { return m_allowImage; }
6617    bool allowImageSlice() const { return m_allowImageSlice; }
6618    bool allowRepeat() const { return m_allowRepeat; }
6619    bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; }
6620
6621    bool requireWidth() const { return m_requireWidth; }
6622    bool requireOutset() const { return m_requireOutset; }
6623
6624    void commitImage(PassRefPtr<CSSValue> image)
6625    {
6626        m_image = image;
6627        m_canAdvance = true;
6628        m_allowCommit = true;
6629        m_allowImage = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
6630        m_allowImageSlice = !m_imageSlice;
6631        m_allowRepeat = !m_repeat;
6632    }
6633    void commitImageSlice(PassRefPtr<CSSBorderImageSliceValue> slice)
6634    {
6635        m_imageSlice = slice;
6636        m_canAdvance = true;
6637        m_allowCommit = m_allowForwardSlashOperator = true;
6638        m_allowImageSlice = m_requireWidth = m_requireOutset = false;
6639        m_allowImage = !m_image;
6640        m_allowRepeat = !m_repeat;
6641    }
6642    void commitForwardSlashOperator()
6643    {
6644        m_canAdvance = true;
6645        m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowForwardSlashOperator = false;
6646        if (!m_borderSlice) {
6647            m_requireWidth = true;
6648            m_requireOutset = false;
6649        } else {
6650            m_requireOutset = true;
6651            m_requireWidth = false;
6652        }
6653    }
6654    void commitBorderWidth(PassRefPtr<CSSPrimitiveValue> slice)
6655    {
6656        m_borderSlice = slice;
6657        m_canAdvance = true;
6658        m_allowCommit = m_allowForwardSlashOperator = true;
6659        m_allowImageSlice = m_requireWidth = m_requireOutset = false;
6660        m_allowImage = !m_image;
6661        m_allowRepeat = !m_repeat;
6662    }
6663    void commitBorderOutset(PassRefPtr<CSSPrimitiveValue> outset)
6664    {
6665        m_outset = outset;
6666        m_canAdvance = true;
6667        m_allowCommit = true;
6668        m_allowImageSlice = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
6669        m_allowImage = !m_image;
6670        m_allowRepeat = !m_repeat;
6671    }
6672    void commitRepeat(PassRefPtr<CSSValue> repeat)
6673    {
6674        m_repeat = repeat;
6675        m_canAdvance = true;
6676        m_allowCommit = true;
6677        m_allowRepeat = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
6678        m_allowImageSlice = !m_imageSlice;
6679        m_allowImage = !m_image;
6680    }
6681
6682    PassRefPtr<CSSValue> commitWebKitBorderImage()
6683    {
6684        return createBorderImageValue(m_image, m_imageSlice, m_borderSlice, m_outset, m_repeat);
6685    }
6686
6687    void commitBorderImage(CSSParser* parser, bool important)
6688    {
6689        commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
6690        commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice, important);
6691        commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice, important);
6692        commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset, important);
6693        commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important);
6694    }
6695
6696    void commitBorderImageProperty(CSSPropertyID propId, CSSParser* parser, PassRefPtr<CSSValue> value, bool important)
6697    {
6698        if (value)
6699            parser->addProperty(propId, value, important);
6700        else
6701            parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true);
6702    }
6703
6704    bool m_canAdvance;
6705
6706    bool m_allowCommit;
6707    bool m_allowImage;
6708    bool m_allowImageSlice;
6709    bool m_allowRepeat;
6710    bool m_allowForwardSlashOperator;
6711
6712    bool m_requireWidth;
6713    bool m_requireOutset;
6714
6715    RefPtr<CSSValue> m_image;
6716    RefPtr<CSSBorderImageSliceValue> m_imageSlice;
6717    RefPtr<CSSPrimitiveValue> m_borderSlice;
6718    RefPtr<CSSPrimitiveValue> m_outset;
6719
6720    RefPtr<CSSValue> m_repeat;
6721};
6722
6723bool CSSParser::parseBorderImage(CSSPropertyID propId, RefPtr<CSSValue>& result, bool important)
6724{
6725    ShorthandScope scope(this, propId);
6726    BorderImageParseContext context;
6727    while (CSSParserValue* val = m_valueList->current()) {
6728        context.setCanAdvance(false);
6729
6730        if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(val))
6731            context.commitForwardSlashOperator();
6732
6733        if (!context.canAdvance() && context.allowImage()) {
6734            if (val->unit == CSSPrimitiveValue::CSS_URI)
6735                context.commitImage(CSSImageValue::create(completeURL(val->string)));
6736            else if (isGeneratedImageValue(val)) {
6737                RefPtr<CSSValue> value;
6738                if (parseGeneratedImage(m_valueList.get(), value))
6739                    context.commitImage(value.release());
6740                else
6741                    return false;
6742#if ENABLE(CSS_IMAGE_SET)
6743            } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
6744                RefPtr<CSSValue> value = parseImageSet();
6745                if (value)
6746                    context.commitImage(value.release());
6747                else
6748                    return false;
6749#endif
6750            } else if (val->id == CSSValueNone)
6751                context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone));
6752        }
6753
6754        if (!context.canAdvance() && context.allowImageSlice()) {
6755            RefPtr<CSSBorderImageSliceValue> imageSlice;
6756            if (parseBorderImageSlice(propId, imageSlice))
6757                context.commitImageSlice(imageSlice.release());
6758        }
6759
6760        if (!context.canAdvance() && context.allowRepeat()) {
6761            RefPtr<CSSValue> repeat;
6762            if (parseBorderImageRepeat(repeat))
6763                context.commitRepeat(repeat.release());
6764        }
6765
6766        if (!context.canAdvance() && context.requireWidth()) {
6767            RefPtr<CSSPrimitiveValue> borderSlice;
6768            if (parseBorderImageWidth(borderSlice))
6769                context.commitBorderWidth(borderSlice.release());
6770        }
6771
6772        if (!context.canAdvance() && context.requireOutset()) {
6773            RefPtr<CSSPrimitiveValue> borderOutset;
6774            if (parseBorderImageOutset(borderOutset))
6775                context.commitBorderOutset(borderOutset.release());
6776        }
6777
6778        if (!context.canAdvance())
6779            return false;
6780
6781        m_valueList->next();
6782    }
6783
6784    if (context.allowCommit()) {
6785        if (propId == CSSPropertyBorderImage)
6786            context.commitBorderImage(this, important);
6787        else
6788            // Need to fully commit as a single value.
6789            result = context.commitWebKitBorderImage();
6790        return true;
6791    }
6792
6793    return false;
6794}
6795
6796static bool isBorderImageRepeatKeyword(int id)
6797{
6798    return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
6799}
6800
6801bool CSSParser::parseBorderImageRepeat(RefPtr<CSSValue>& result)
6802{
6803    RefPtr<CSSPrimitiveValue> firstValue;
6804    RefPtr<CSSPrimitiveValue> secondValue;
6805    CSSParserValue* val = m_valueList->current();
6806    if (!val)
6807        return false;
6808    if (isBorderImageRepeatKeyword(val->id))
6809        firstValue = cssValuePool().createIdentifierValue(val->id);
6810    else
6811        return false;
6812
6813    val = m_valueList->next();
6814    if (val) {
6815        if (isBorderImageRepeatKeyword(val->id))
6816            secondValue = cssValuePool().createIdentifierValue(val->id);
6817        else if (!inShorthand()) {
6818            // If we're not parsing a shorthand then we are invalid.
6819            return false;
6820        } else {
6821            // We need to rewind the value list, so that when its advanced we'll
6822            // end up back at this value.
6823            m_valueList->previous();
6824            secondValue = firstValue;
6825        }
6826    } else
6827        secondValue = firstValue;
6828
6829    result = createPrimitiveValuePair(firstValue, secondValue);
6830    return true;
6831}
6832
6833class BorderImageSliceParseContext {
6834public:
6835    BorderImageSliceParseContext(CSSParser* parser)
6836    : m_parser(parser)
6837    , m_allowNumber(true)
6838    , m_allowFill(true)
6839    , m_allowFinalCommit(false)
6840    , m_fill(false)
6841    { }
6842
6843    bool allowNumber() const { return m_allowNumber; }
6844    bool allowFill() const { return m_allowFill; }
6845    bool allowFinalCommit() const { return m_allowFinalCommit; }
6846    CSSPrimitiveValue* top() const { return m_top.get(); }
6847
6848    void commitNumber(CSSParserValue* v)
6849    {
6850        RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
6851        if (!m_top)
6852            m_top = val;
6853        else if (!m_right)
6854            m_right = val;
6855        else if (!m_bottom)
6856            m_bottom = val;
6857        else {
6858            ASSERT(!m_left);
6859            m_left = val;
6860        }
6861
6862        m_allowNumber = !m_left;
6863        m_allowFinalCommit = true;
6864    }
6865
6866    void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; }
6867
6868    PassRefPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
6869    {
6870        // We need to clone and repeat values for any omissions.
6871        ASSERT(m_top);
6872        if (!m_right) {
6873            m_right = m_top;
6874            m_bottom = m_top;
6875            m_left = m_top;
6876        }
6877        if (!m_bottom) {
6878            m_bottom = m_top;
6879            m_left = m_right;
6880        }
6881        if (!m_left)
6882            m_left = m_right;
6883
6884        // Now build a rect value to hold all four of our primitive values.
6885        RefPtr<Quad> quad = Quad::create();
6886        quad->setTop(m_top);
6887        quad->setRight(m_right);
6888        quad->setBottom(m_bottom);
6889        quad->setLeft(m_left);
6890
6891        // Make our new border image value now.
6892        return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill);
6893    }
6894
6895private:
6896    CSSParser* m_parser;
6897
6898    bool m_allowNumber;
6899    bool m_allowFill;
6900    bool m_allowFinalCommit;
6901
6902    RefPtr<CSSPrimitiveValue> m_top;
6903    RefPtr<CSSPrimitiveValue> m_right;
6904    RefPtr<CSSPrimitiveValue> m_bottom;
6905    RefPtr<CSSPrimitiveValue> m_left;
6906
6907    bool m_fill;
6908};
6909
6910bool CSSParser::parseBorderImageSlice(CSSPropertyID propId, RefPtr<CSSBorderImageSliceValue>& result)
6911{
6912    BorderImageSliceParseContext context(this);
6913    CSSParserValue* val;
6914    while ((val = m_valueList->current())) {
6915        // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
6916        if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, CSSStrictMode)) {
6917            context.commitNumber(val);
6918        } else if (context.allowFill() && val->id == CSSValueFill)
6919            context.commitFill();
6920        else if (!inShorthand()) {
6921            // If we're not parsing a shorthand then we are invalid.
6922            return false;
6923        } else {
6924            if (context.allowFinalCommit()) {
6925                // We're going to successfully parse, but we don't want to consume this token.
6926                m_valueList->previous();
6927            }
6928            break;
6929        }
6930        m_valueList->next();
6931    }
6932
6933    if (context.allowFinalCommit()) {
6934        // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
6935        // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
6936        if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
6937            context.commitFill();
6938
6939        // Need to fully commit as a single value.
6940        result = context.commitBorderImageSlice();
6941        return true;
6942    }
6943
6944    return false;
6945}
6946
6947class BorderImageQuadParseContext {
6948public:
6949    BorderImageQuadParseContext(CSSParser* parser)
6950    : m_parser(parser)
6951    , m_allowNumber(true)
6952    , m_allowFinalCommit(false)
6953    { }
6954
6955    bool allowNumber() const { return m_allowNumber; }
6956    bool allowFinalCommit() const { return m_allowFinalCommit; }
6957    CSSPrimitiveValue* top() const { return m_top.get(); }
6958
6959    void commitNumber(CSSParserValue* v)
6960    {
6961        RefPtr<CSSPrimitiveValue> val;
6962        if (v->id == CSSValueAuto)
6963            val = cssValuePool().createIdentifierValue(v->id);
6964        else
6965            val = m_parser->createPrimitiveNumericValue(v);
6966
6967        if (!m_top)
6968            m_top = val;
6969        else if (!m_right)
6970            m_right = val;
6971        else if (!m_bottom)
6972            m_bottom = val;
6973        else {
6974            ASSERT(!m_left);
6975            m_left = val;
6976        }
6977
6978        m_allowNumber = !m_left;
6979        m_allowFinalCommit = true;
6980    }
6981
6982    void setAllowFinalCommit() { m_allowFinalCommit = true; }
6983    void setTop(PassRefPtr<CSSPrimitiveValue> val) { m_top = val; }
6984
6985    PassRefPtr<CSSPrimitiveValue> commitBorderImageQuad()
6986    {
6987        // We need to clone and repeat values for any omissions.
6988        ASSERT(m_top);
6989        if (!m_right) {
6990            m_right = m_top;
6991            m_bottom = m_top;
6992            m_left = m_top;
6993        }
6994        if (!m_bottom) {
6995            m_bottom = m_top;
6996            m_left = m_right;
6997        }
6998        if (!m_left)
6999            m_left = m_right;
7000
7001        // Now build a quad value to hold all four of our primitive values.
7002        RefPtr<Quad> quad = Quad::create();
7003        quad->setTop(m_top);
7004        quad->setRight(m_right);
7005        quad->setBottom(m_bottom);
7006        quad->setLeft(m_left);
7007
7008        // Make our new value now.
7009        return cssValuePool().createValue(quad.release());
7010    }
7011
7012private:
7013    CSSParser* m_parser;
7014
7015    bool m_allowNumber;
7016    bool m_allowFinalCommit;
7017
7018    RefPtr<CSSPrimitiveValue> m_top;
7019    RefPtr<CSSPrimitiveValue> m_right;
7020    RefPtr<CSSPrimitiveValue> m_bottom;
7021    RefPtr<CSSPrimitiveValue> m_left;
7022};
7023
7024bool CSSParser::parseBorderImageQuad(Units validUnits, RefPtr<CSSPrimitiveValue>& result)
7025{
7026    BorderImageQuadParseContext context(this);
7027    CSSParserValue* val;
7028    while ((val = m_valueList->current())) {
7029        if (context.allowNumber() && (validUnit(val, validUnits, CSSStrictMode) || val->id == CSSValueAuto)) {
7030            context.commitNumber(val);
7031        } else if (!inShorthand()) {
7032            // If we're not parsing a shorthand then we are invalid.
7033            return false;
7034        } else {
7035            if (context.allowFinalCommit())
7036                m_valueList->previous(); // The shorthand loop will advance back to this point.
7037            break;
7038        }
7039        m_valueList->next();
7040    }
7041
7042    if (context.allowFinalCommit()) {
7043        // Need to fully commit as a single value.
7044        result = context.commitBorderImageQuad();
7045        return true;
7046    }
7047    return false;
7048}
7049
7050bool CSSParser::parseBorderImageWidth(RefPtr<CSSPrimitiveValue>& result)
7051{
7052    return parseBorderImageQuad(FLength | FInteger | FNonNeg | FPercent, result);
7053}
7054
7055bool CSSParser::parseBorderImageOutset(RefPtr<CSSPrimitiveValue>& result)
7056{
7057    return parseBorderImageQuad(FLength | FInteger | FNonNeg, result);
7058}
7059
7060static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4])
7061{
7062    if (radii[3])
7063        return;
7064    if (!radii[2]) {
7065        if (!radii[1])
7066            radii[1] = radii[0];
7067        radii[2] = radii[0];
7068    }
7069    radii[3] = radii[1];
7070}
7071
7072bool CSSParser::parseBorderRadius(CSSPropertyID propId, bool important)
7073{
7074    unsigned num = m_valueList->size();
7075    if (num > 9)
7076        return false;
7077
7078    ShorthandScope scope(this, propId);
7079    RefPtr<CSSPrimitiveValue> radii[2][4];
7080
7081    unsigned indexAfterSlash = 0;
7082    for (unsigned i = 0; i < num; ++i) {
7083        CSSParserValue* value = m_valueList->valueAt(i);
7084        if (value->unit == CSSParserValue::Operator) {
7085            if (value->iValue != '/')
7086                return false;
7087
7088            if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
7089                return false;
7090
7091            indexAfterSlash = i + 1;
7092            completeBorderRadii(radii[0]);
7093            continue;
7094        }
7095
7096        if (i - indexAfterSlash >= 4)
7097            return false;
7098
7099        if (!validUnit(value, FLength | FPercent | FNonNeg))
7100            return false;
7101
7102        RefPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
7103
7104        if (!indexAfterSlash) {
7105            radii[0][i] = radius;
7106
7107            // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
7108            if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
7109                indexAfterSlash = 1;
7110                completeBorderRadii(radii[0]);
7111            }
7112        } else
7113            radii[1][i - indexAfterSlash] = radius.release();
7114    }
7115
7116    if (!indexAfterSlash) {
7117        completeBorderRadii(radii[0]);
7118        for (unsigned i = 0; i < 4; ++i)
7119            radii[1][i] = radii[0][i];
7120    } else
7121        completeBorderRadii(radii[1]);
7122
7123    ImplicitScope implicitScope(this, PropertyImplicit);
7124    addProperty(CSSPropertyBorderTopLeftRadius, createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()), important);
7125    addProperty(CSSPropertyBorderTopRightRadius, createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()), important);
7126    addProperty(CSSPropertyBorderBottomRightRadius, createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()), important);
7127    addProperty(CSSPropertyBorderBottomLeftRadius, createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()), important);
7128    return true;
7129}
7130
7131bool CSSParser::parseAspectRatio(bool important)
7132{
7133    unsigned num = m_valueList->size();
7134    if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
7135        addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(CSSValueNone), important);
7136        return true;
7137    }
7138
7139    if (num != 3)
7140        return false;
7141
7142    CSSParserValue* lvalue = m_valueList->valueAt(0);
7143    CSSParserValue* op = m_valueList->valueAt(1);
7144    CSSParserValue* rvalue = m_valueList->valueAt(2);
7145
7146    if (!isForwardSlashOperator(op))
7147        return false;
7148
7149    if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
7150        return false;
7151
7152    if (!lvalue->fValue || !rvalue->fValue)
7153        return false;
7154
7155    addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important);
7156
7157    return true;
7158}
7159
7160bool CSSParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important)
7161{
7162    enum { ID, VAL } state = ID;
7163
7164    RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
7165    RefPtr<CSSPrimitiveValue> counterName;
7166
7167    while (true) {
7168        CSSParserValue* val = m_valueList->current();
7169        switch (state) {
7170            case ID:
7171                if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
7172                    counterName = createPrimitiveStringValue(val);
7173                    state = VAL;
7174                    m_valueList->next();
7175                    continue;
7176                }
7177                break;
7178            case VAL: {
7179                int i = defaultValue;
7180                if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
7181                    i = clampToInteger(val->fValue);
7182                    m_valueList->next();
7183                }
7184
7185                list->append(createPrimitiveValuePair(counterName.release(),
7186                    cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER)));
7187                state = ID;
7188                continue;
7189            }
7190        }
7191        break;
7192    }
7193
7194    if (list->length() > 0) {
7195        addProperty(propId, list.release(), important);
7196        return true;
7197    }
7198
7199    return false;
7200}
7201
7202// This should go away once we drop support for -webkit-gradient
7203static PassRefPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
7204{
7205    RefPtr<CSSPrimitiveValue> result;
7206    if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
7207        if ((equalIgnoringCase(a, "left") && horizontal)
7208            || (equalIgnoringCase(a, "top") && !horizontal))
7209            result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
7210        else if ((equalIgnoringCase(a, "right") && horizontal)
7211                 || (equalIgnoringCase(a, "bottom") && !horizontal))
7212            result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
7213        else if (equalIgnoringCase(a, "center"))
7214            result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
7215    } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7216        result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(a->unit));
7217    return result;
7218}
7219
7220static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
7221{
7222    if (a->unit != CSSParserValue::Function)
7223        return false;
7224
7225    if (!equalIgnoringCase(a->function->name, "from(") &&
7226        !equalIgnoringCase(a->function->name, "to(") &&
7227        !equalIgnoringCase(a->function->name, "color-stop("))
7228        return false;
7229
7230    CSSParserValueList* args = a->function->args.get();
7231    if (!args)
7232        return false;
7233
7234    if (equalIgnoringCase(a->function->name, "from(")
7235        || equalIgnoringCase(a->function->name, "to(")) {
7236        // The "from" and "to" stops expect 1 argument.
7237        if (args->size() != 1)
7238            return false;
7239
7240        if (equalIgnoringCase(a->function->name, "from("))
7241            stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
7242        else
7243            stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
7244
7245        int id = args->current()->id;
7246        if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
7247            stop.m_color = cssValuePool().createIdentifierValue(id);
7248        else
7249            stop.m_color = p->parseColor(args->current());
7250        if (!stop.m_color)
7251            return false;
7252    }
7253
7254    // The "color-stop" function expects 3 arguments.
7255    if (equalIgnoringCase(a->function->name, "color-stop(")) {
7256        if (args->size() != 3)
7257            return false;
7258
7259        CSSParserValue* stopArg = args->current();
7260        if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7261            stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
7262        else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
7263            stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
7264        else
7265            return false;
7266
7267        stopArg = args->next();
7268        if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
7269            return false;
7270
7271        stopArg = args->next();
7272        int id = stopArg->id;
7273        if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
7274            stop.m_color = cssValuePool().createIdentifierValue(id);
7275        else
7276            stop.m_color = p->parseColor(stopArg);
7277        if (!stop.m_color)
7278            return false;
7279    }
7280
7281    return true;
7282}
7283
7284bool CSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient)
7285{
7286    // Walk the arguments.
7287    CSSParserValueList* args = valueList->current()->function->args.get();
7288    if (!args || args->size() == 0)
7289        return false;
7290
7291    // The first argument is the gradient type.  It is an identifier.
7292    CSSGradientType gradientType;
7293    CSSParserValue* a = args->current();
7294    if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
7295        return false;
7296    if (equalIgnoringCase(a, "linear"))
7297        gradientType = CSSDeprecatedLinearGradient;
7298    else if (equalIgnoringCase(a, "radial"))
7299        gradientType = CSSDeprecatedRadialGradient;
7300    else
7301        return false;
7302
7303    RefPtr<CSSGradientValue> result;
7304    switch (gradientType) {
7305    case CSSDeprecatedLinearGradient:
7306        result = CSSLinearGradientValue::create(NonRepeating, gradientType);
7307        break;
7308    case CSSDeprecatedRadialGradient:
7309        result = CSSRadialGradientValue::create(NonRepeating, gradientType);
7310        break;
7311    default:
7312        // The rest of the gradient types shouldn't appear here.
7313        ASSERT_NOT_REACHED();
7314    }
7315
7316    // Comma.
7317    a = args->next();
7318    if (!isComma(a))
7319        return false;
7320
7321    // Next comes the starting point for the gradient as an x y pair.  There is no
7322    // comma between the x and the y values.
7323    // First X.  It can be left, right, number or percent.
7324    a = args->next();
7325    if (!a)
7326        return false;
7327    RefPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
7328    if (!point)
7329        return false;
7330    result->setFirstX(point.release());
7331
7332    // First Y.  It can be top, bottom, number or percent.
7333    a = args->next();
7334    if (!a)
7335        return false;
7336    point = parseDeprecatedGradientPoint(a, false);
7337    if (!point)
7338        return false;
7339    result->setFirstY(point.release());
7340
7341    // Comma after the first point.
7342    a = args->next();
7343    if (!isComma(a))
7344        return false;
7345
7346    // For radial gradients only, we now expect a numeric radius.
7347    if (gradientType == CSSDeprecatedRadialGradient) {
7348        a = args->next();
7349        if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
7350            return false;
7351        static_cast<CSSRadialGradientValue*>(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
7352
7353        // Comma after the first radius.
7354        a = args->next();
7355        if (!isComma(a))
7356            return false;
7357    }
7358
7359    // Next is the ending point for the gradient as an x, y pair.
7360    // Second X.  It can be left, right, number or percent.
7361    a = args->next();
7362    if (!a)
7363        return false;
7364    point = parseDeprecatedGradientPoint(a, true);
7365    if (!point)
7366        return false;
7367    result->setSecondX(point.release());
7368
7369    // Second Y.  It can be top, bottom, number or percent.
7370    a = args->next();
7371    if (!a)
7372        return false;
7373    point = parseDeprecatedGradientPoint(a, false);
7374    if (!point)
7375        return false;
7376    result->setSecondY(point.release());
7377
7378    // For radial gradients only, we now expect the second radius.
7379    if (gradientType == CSSDeprecatedRadialGradient) {
7380        // Comma after the second point.
7381        a = args->next();
7382        if (!isComma(a))
7383            return false;
7384
7385        a = args->next();
7386        if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
7387            return false;
7388        static_cast<CSSRadialGradientValue*>(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
7389    }
7390
7391    // We now will accept any number of stops (0 or more).
7392    a = args->next();
7393    while (a) {
7394        // Look for the comma before the next stop.
7395        if (!isComma(a))
7396            return false;
7397
7398        // Now examine the stop itself.
7399        a = args->next();
7400        if (!a)
7401            return false;
7402
7403        // The function name needs to be one of "from", "to", or "color-stop."
7404        CSSGradientColorStop stop;
7405        if (!parseDeprecatedGradientColorStop(this, a, stop))
7406            return false;
7407        result->addStop(stop);
7408
7409        // Advance
7410        a = args->next();
7411    }
7412
7413    gradient = result.release();
7414    return true;
7415}
7416
7417static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
7418{
7419    if (a->unit != CSSPrimitiveValue::CSS_IDENT)
7420        return 0;
7421
7422    switch (a->id) {
7423        case CSSValueLeft:
7424        case CSSValueRight:
7425            isHorizontal = true;
7426            break;
7427        case CSSValueTop:
7428        case CSSValueBottom:
7429            isHorizontal = false;
7430            break;
7431        default:
7432            return 0;
7433    }
7434    return cssValuePool().createIdentifierValue(a->id);
7435}
7436
7437static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSParser* p, CSSParserValue* value)
7438{
7439    int id = value->id;
7440    if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
7441        return cssValuePool().createIdentifierValue(id);
7442
7443    return p->parseColor(value);
7444}
7445
7446bool CSSParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7447{
7448    RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient);
7449
7450    // Walk the arguments.
7451    CSSParserValueList* args = valueList->current()->function->args.get();
7452    if (!args || !args->size())
7453        return false;
7454
7455    CSSParserValue* a = args->current();
7456    if (!a)
7457        return false;
7458
7459    bool expectComma = false;
7460    // Look for angle.
7461    if (validUnit(a, FAngle, CSSStrictMode)) {
7462        result->setAngle(createPrimitiveNumericValue(a));
7463
7464        args->next();
7465        expectComma = true;
7466    } else {
7467        // Look one or two optional keywords that indicate a side or corner.
7468        RefPtr<CSSPrimitiveValue> startX, startY;
7469
7470        RefPtr<CSSPrimitiveValue> location;
7471        bool isHorizontal = false;
7472        if ((location = valueFromSideKeyword(a, isHorizontal))) {
7473            if (isHorizontal)
7474                startX = location;
7475            else
7476                startY = location;
7477
7478            if ((a = args->next())) {
7479                if ((location = valueFromSideKeyword(a, isHorizontal))) {
7480                    if (isHorizontal) {
7481                        if (startX)
7482                            return false;
7483                        startX = location;
7484                    } else {
7485                        if (startY)
7486                            return false;
7487                        startY = location;
7488                    }
7489
7490                    args->next();
7491                }
7492            }
7493
7494            expectComma = true;
7495        }
7496
7497        if (!startX && !startY)
7498            startY = cssValuePool().createIdentifierValue(CSSValueTop);
7499
7500        result->setFirstX(startX.release());
7501        result->setFirstY(startY.release());
7502    }
7503
7504    if (!parseGradientColorStops(args, result.get(), expectComma))
7505        return false;
7506
7507    if (!result->stopCount())
7508        return false;
7509
7510    gradient = result.release();
7511    return true;
7512}
7513
7514bool CSSParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7515{
7516    RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
7517
7518    // Walk the arguments.
7519    CSSParserValueList* args = valueList->current()->function->args.get();
7520    if (!args || !args->size())
7521        return false;
7522
7523    CSSParserValue* a = args->current();
7524    if (!a)
7525        return false;
7526
7527    bool expectComma = false;
7528
7529    // Optional background-position
7530    RefPtr<CSSValue> centerX;
7531    RefPtr<CSSValue> centerY;
7532    // parse2ValuesFillPosition advances the args next pointer.
7533    parse2ValuesFillPosition(args, centerX, centerY);
7534    a = args->current();
7535    if (!a)
7536        return false;
7537
7538    if (centerX || centerY) {
7539        // Comma
7540        if (!isComma(a))
7541            return false;
7542
7543        a = args->next();
7544        if (!a)
7545            return false;
7546    }
7547
7548    ASSERT(!centerX || centerX->isPrimitiveValue());
7549    ASSERT(!centerY || centerY->isPrimitiveValue());
7550
7551    result->setFirstX(static_cast<CSSPrimitiveValue*>(centerX.get()));
7552    result->setSecondX(static_cast<CSSPrimitiveValue*>(centerX.get()));
7553    // CSS3 radial gradients always share the same start and end point.
7554    result->setFirstY(static_cast<CSSPrimitiveValue*>(centerY.get()));
7555    result->setSecondY(static_cast<CSSPrimitiveValue*>(centerY.get()));
7556
7557    RefPtr<CSSPrimitiveValue> shapeValue;
7558    RefPtr<CSSPrimitiveValue> sizeValue;
7559
7560    // Optional shape and/or size in any order.
7561    for (int i = 0; i < 2; ++i) {
7562        if (a->unit != CSSPrimitiveValue::CSS_IDENT)
7563            break;
7564
7565        bool foundValue = false;
7566        switch (a->id) {
7567        case CSSValueCircle:
7568        case CSSValueEllipse:
7569            shapeValue = cssValuePool().createIdentifierValue(a->id);
7570            foundValue = true;
7571            break;
7572        case CSSValueClosestSide:
7573        case CSSValueClosestCorner:
7574        case CSSValueFarthestSide:
7575        case CSSValueFarthestCorner:
7576        case CSSValueContain:
7577        case CSSValueCover:
7578            sizeValue = cssValuePool().createIdentifierValue(a->id);
7579            foundValue = true;
7580            break;
7581        }
7582
7583        if (foundValue) {
7584            a = args->next();
7585            if (!a)
7586                return false;
7587
7588            expectComma = true;
7589        }
7590    }
7591
7592    result->setShape(shapeValue);
7593    result->setSizingBehavior(sizeValue);
7594
7595    // Or, two lengths or percentages
7596    RefPtr<CSSPrimitiveValue> horizontalSize;
7597    RefPtr<CSSPrimitiveValue> verticalSize;
7598
7599    if (!shapeValue && !sizeValue) {
7600        if (validUnit(a, FLength | FPercent)) {
7601            horizontalSize = createPrimitiveNumericValue(a);
7602            a = args->next();
7603            if (!a)
7604                return false;
7605
7606            expectComma = true;
7607        }
7608
7609        if (validUnit(a, FLength | FPercent)) {
7610            verticalSize = createPrimitiveNumericValue(a);
7611
7612            a = args->next();
7613            if (!a)
7614                return false;
7615            expectComma = true;
7616        }
7617    }
7618
7619    // Must have neither or both.
7620    if (!horizontalSize != !verticalSize)
7621        return false;
7622
7623    result->setEndHorizontalSize(horizontalSize);
7624    result->setEndVerticalSize(verticalSize);
7625
7626    if (!parseGradientColorStops(args, result.get(), expectComma))
7627        return false;
7628
7629    gradient = result.release();
7630    return true;
7631}
7632
7633bool CSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7634{
7635    RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient);
7636
7637    CSSParserValueList* args = valueList->current()->function->args.get();
7638    if (!args || !args->size())
7639        return false;
7640
7641    CSSParserValue* a = args->current();
7642    if (!a)
7643        return false;
7644
7645    bool expectComma = false;
7646    // Look for angle.
7647    if (validUnit(a, FAngle, CSSStrictMode)) {
7648        result->setAngle(createPrimitiveNumericValue(a));
7649
7650        args->next();
7651        expectComma = true;
7652    } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) {
7653        // to [ [left | right] || [top | bottom] ]
7654        a = args->next();
7655        if (!a)
7656            return false;
7657
7658        RefPtr<CSSPrimitiveValue> endX, endY;
7659        RefPtr<CSSPrimitiveValue> location;
7660        bool isHorizontal = false;
7661
7662        location = valueFromSideKeyword(a, isHorizontal);
7663        if (!location)
7664            return false;
7665
7666        if (isHorizontal)
7667            endX = location;
7668        else
7669            endY = location;
7670
7671        a = args->next();
7672        if (!a)
7673            return false;
7674
7675        location = valueFromSideKeyword(a, isHorizontal);
7676        if (location) {
7677            if (isHorizontal) {
7678                if (endX)
7679                    return false;
7680                endX = location;
7681            } else {
7682                if (endY)
7683                    return false;
7684                endY = location;
7685            }
7686
7687            args->next();
7688        }
7689
7690        expectComma = true;
7691        result->setFirstX(endX.release());
7692        result->setFirstY(endY.release());
7693    }
7694
7695    if (!parseGradientColorStops(args, result.get(), expectComma))
7696        return false;
7697
7698    if (!result->stopCount())
7699        return false;
7700
7701    gradient = result.release();
7702    return true;
7703}
7704
7705bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7706{
7707    RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
7708
7709    CSSParserValueList* args = valueList->current()->function->args.get();
7710    if (!args || !args->size())
7711        return false;
7712
7713    CSSParserValue* a = args->current();
7714    if (!a)
7715        return false;
7716
7717    bool expectComma = false;
7718
7719    RefPtr<CSSPrimitiveValue> shapeValue;
7720    RefPtr<CSSPrimitiveValue> sizeValue;
7721    RefPtr<CSSPrimitiveValue> horizontalSize;
7722    RefPtr<CSSPrimitiveValue> verticalSize;
7723
7724    // First part of grammar, the size/shape clause:
7725    // [ circle || <length> ] |
7726    // [ ellipse || [ <length> | <percentage> ]{2} ] |
7727    // [ [ circle | ellipse] || <size-keyword> ]
7728    for (int i = 0; i < 3; ++i) {
7729        if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
7730            bool badIdent = false;
7731            switch (a->id) {
7732            case CSSValueCircle:
7733            case CSSValueEllipse:
7734                if (shapeValue)
7735                    return false;
7736                shapeValue = cssValuePool().createIdentifierValue(a->id);
7737                break;
7738            case CSSValueClosestSide:
7739            case CSSValueClosestCorner:
7740            case CSSValueFarthestSide:
7741            case CSSValueFarthestCorner:
7742                if (sizeValue || horizontalSize)
7743                    return false;
7744                sizeValue = cssValuePool().createIdentifierValue(a->id);
7745                break;
7746            default:
7747                badIdent = true;
7748            }
7749
7750            if (badIdent)
7751                break;
7752
7753            a = args->next();
7754            if (!a)
7755                return false;
7756        } else if (validUnit(a, FLength | FPercent)) {
7757
7758            if (sizeValue || horizontalSize)
7759                return false;
7760            horizontalSize = createPrimitiveNumericValue(a);
7761
7762            a = args->next();
7763            if (!a)
7764                return false;
7765
7766            if (validUnit(a, FLength | FPercent)) {
7767                verticalSize = createPrimitiveNumericValue(a);
7768                ++i;
7769                a = args->next();
7770                if (!a)
7771                    return false;
7772            }
7773        } else
7774            break;
7775    }
7776
7777    // You can specify size as a keyword or a length/percentage, not both.
7778    if (sizeValue && horizontalSize)
7779        return false;
7780    // Circles must have 0 or 1 lengths.
7781    if (shapeValue && shapeValue->getIdent() == CSSValueCircle && verticalSize)
7782        return false;
7783    // Ellipses must have 0 or 2 length/percentages.
7784    if (shapeValue && shapeValue->getIdent() == CSSValueEllipse && horizontalSize && !verticalSize)
7785        return false;
7786    // If there's only one size, it must be a length.
7787    if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
7788        return false;
7789
7790    result->setShape(shapeValue);
7791    result->setSizingBehavior(sizeValue);
7792    result->setEndHorizontalSize(horizontalSize);
7793    result->setEndVerticalSize(verticalSize);
7794
7795    // Second part of grammar, the center-position clause:
7796    // at <position>
7797    RefPtr<CSSValue> centerX;
7798    RefPtr<CSSValue> centerY;
7799    if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) {
7800        a = args->next();
7801        if (!a)
7802            return false;
7803
7804        parseFillPosition(args, centerX, centerY);
7805        ASSERT(centerX->isPrimitiveValue());
7806        ASSERT(centerY->isPrimitiveValue());
7807        if (!(centerX && centerY))
7808            return false;
7809
7810        a = args->current();
7811        if (!a)
7812            return false;
7813        result->setFirstX(static_cast<CSSPrimitiveValue*>(centerX.get()));
7814        result->setFirstY(static_cast<CSSPrimitiveValue*>(centerY.get()));
7815        // Right now, CSS radial gradients have the same start and end centers.
7816        result->setSecondX(static_cast<CSSPrimitiveValue*>(centerX.get()));
7817        result->setSecondY(static_cast<CSSPrimitiveValue*>(centerY.get()));
7818    }
7819
7820    if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
7821        expectComma = true;
7822
7823    if (!parseGradientColorStops(args, result.get(), expectComma))
7824        return false;
7825
7826    gradient = result.release();
7827    return true;
7828}
7829
7830bool CSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
7831{
7832    CSSParserValue* a = valueList->current();
7833
7834    // Now look for color stops.
7835    while (a) {
7836        // Look for the comma before the next stop.
7837        if (expectComma) {
7838            if (!isComma(a))
7839                return false;
7840
7841            a = valueList->next();
7842            if (!a)
7843                return false;
7844        }
7845
7846        // <color-stop> = <color> [ <percentage> | <length> ]?
7847        CSSGradientColorStop stop;
7848        stop.m_color = parseGradientColorOrKeyword(this, a);
7849        if (!stop.m_color)
7850            return false;
7851
7852        a = valueList->next();
7853        if (a) {
7854            if (validUnit(a, FLength | FPercent)) {
7855                stop.m_position = createPrimitiveNumericValue(a);
7856                a = valueList->next();
7857            }
7858        }
7859
7860        gradient->addStop(stop);
7861        expectComma = true;
7862    }
7863
7864    // Must have 2 or more stops to be valid.
7865    return gradient->stopCount() >= 2;
7866}
7867
7868bool CSSParser::isGeneratedImageValue(CSSParserValue* val) const
7869{
7870    if (val->unit != CSSParserValue::Function)
7871        return false;
7872
7873    return equalIgnoringCase(val->function->name, "-webkit-gradient(")
7874        || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
7875        || equalIgnoringCase(val->function->name, "linear-gradient(")
7876        || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
7877        || equalIgnoringCase(val->function->name, "repeating-linear-gradient(")
7878        || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
7879        || equalIgnoringCase(val->function->name, "radial-gradient(")
7880        || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
7881        || equalIgnoringCase(val->function->name, "repeating-radial-gradient(")
7882        || equalIgnoringCase(val->function->name, "-webkit-canvas(")
7883        || equalIgnoringCase(val->function->name, "-webkit-cross-fade(");
7884}
7885
7886bool CSSParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
7887{
7888    CSSParserValue* val = valueList->current();
7889
7890    if (val->unit != CSSParserValue::Function)
7891        return false;
7892
7893    if (equalIgnoringCase(val->function->name, "-webkit-gradient("))
7894        return parseDeprecatedGradient(valueList, value);
7895
7896    if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient("))
7897        return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
7898
7899    if (equalIgnoringCase(val->function->name, "linear-gradient("))
7900        return parseLinearGradient(valueList, value, NonRepeating);
7901
7902    if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient("))
7903        return parseDeprecatedLinearGradient(valueList, value, Repeating);
7904
7905    if (equalIgnoringCase(val->function->name, "repeating-linear-gradient("))
7906        return parseLinearGradient(valueList, value, Repeating);
7907
7908    if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient("))
7909        return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
7910
7911    if (equalIgnoringCase(val->function->name, "radial-gradient("))
7912        return parseRadialGradient(valueList, value, NonRepeating);
7913
7914    if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient("))
7915        return parseDeprecatedRadialGradient(valueList, value, Repeating);
7916
7917    if (equalIgnoringCase(val->function->name, "repeating-radial-gradient("))
7918        return parseRadialGradient(valueList, value, Repeating);
7919
7920    if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
7921        return parseCanvas(valueList, value);
7922
7923    if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
7924        return parseCrossfade(valueList, value);
7925
7926    return false;
7927}
7928
7929bool CSSParser::parseCrossfade(CSSParserValueList* valueList, RefPtr<CSSValue>& crossfade)
7930{
7931    RefPtr<CSSCrossfadeValue> result;
7932
7933    // Walk the arguments.
7934    CSSParserValueList* args = valueList->current()->function->args.get();
7935    if (!args || args->size() != 5)
7936        return false;
7937    CSSParserValue* a = args->current();
7938    RefPtr<CSSValue> fromImageValue;
7939    RefPtr<CSSValue> toImageValue;
7940
7941    // The first argument is the "from" image. It is a fill image.
7942    if (!a || !parseFillImage(args, fromImageValue))
7943        return false;
7944    a = args->next();
7945
7946    // Skip a comma
7947    if (!isComma(a))
7948        return false;
7949    a = args->next();
7950
7951    // The second argument is the "to" image. It is a fill image.
7952    if (!a || !parseFillImage(args, toImageValue))
7953        return false;
7954    a = args->next();
7955
7956    // Skip a comma
7957    if (!isComma(a))
7958        return false;
7959    a = args->next();
7960
7961    // The third argument is the crossfade value. It is a percentage or a fractional number.
7962    RefPtr<CSSPrimitiveValue> percentage;
7963    if (!a)
7964        return false;
7965
7966    if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7967        percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
7968    else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
7969        percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
7970    else
7971        return false;
7972
7973    result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
7974    result->setPercentage(percentage);
7975
7976    crossfade = result;
7977
7978    return true;
7979}
7980
7981bool CSSParser::parseCanvas(CSSParserValueList* valueList, RefPtr<CSSValue>& canvas)
7982{
7983    // Walk the arguments.
7984    CSSParserValueList* args = valueList->current()->function->args.get();
7985    if (!args || args->size() != 1)
7986        return false;
7987
7988    // The first argument is the canvas name.  It is an identifier.
7989    CSSParserValue* value = args->current();
7990    if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
7991        return false;
7992
7993    canvas = CSSCanvasValue::create(value->string);
7994    return true;
7995}
7996
7997#if ENABLE(CSS_IMAGE_RESOLUTION)
7998PassRefPtr<CSSValue> CSSParser::parseImageResolution()
7999{
8000    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8001    bool haveResolution = false;
8002    bool haveFromImage = false;
8003    bool haveSnap = false;
8004
8005    CSSParserValue* value = m_valueList->current();
8006    while (value) {
8007        if (!haveFromImage && value->id == CSSValueFromImage) {
8008            list->append(cssValuePool().createIdentifierValue(value->id));
8009            haveFromImage = true;
8010        } else if (!haveSnap && value->id == CSSValueSnap) {
8011            list->append(cssValuePool().createIdentifierValue(value->id));
8012            haveSnap = true;
8013        } else if (!haveResolution && validUnit(value, FResolution | FNonNeg) && value->fValue > 0) {
8014            list->append(createPrimitiveNumericValue(value));
8015            haveResolution = true;
8016        } else
8017            return 0;
8018        value = m_valueList->next();
8019    }
8020    if (!list->length())
8021        return 0;
8022    if (!haveFromImage && !haveResolution)
8023        return 0;
8024    return list.release();
8025}
8026#endif
8027
8028#if ENABLE(CSS_IMAGE_SET)
8029PassRefPtr<CSSValue> CSSParser::parseImageSet()
8030{
8031    CSSParserValue* value = m_valueList->current();
8032    ASSERT(value->unit == CSSParserValue::Function);
8033
8034    CSSParserValueList* functionArgs = value->function->args.get();
8035    if (!functionArgs || !functionArgs->size() || !functionArgs->current())
8036        return 0;
8037
8038    RefPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
8039    CSSParserValue* arg = functionArgs->current();
8040    while (arg) {
8041        if (arg->unit != CSSPrimitiveValue::CSS_URI)
8042            return 0;
8043
8044        imageSet->append(CSSImageValue::create(completeURL(arg->string)));
8045        arg = functionArgs->next();
8046        if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
8047            return 0;
8048
8049        double imageScaleFactor = 0;
8050        const String& string = arg->string;
8051        unsigned length = string.length();
8052        if (!length)
8053            return 0;
8054        if (string.is8Bit()) {
8055            const LChar* start = string.characters8();
8056            parseDouble(start, start + length, 'x', imageScaleFactor);
8057        } else {
8058            const UChar* start = string.characters();
8059            parseDouble(start, start + length, 'x', imageScaleFactor);
8060        }
8061        if (imageScaleFactor <= 0)
8062            return 0;
8063        imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER));
8064
8065        // If there are no more arguments, we're done.
8066        arg = functionArgs->next();
8067        if (!arg)
8068            break;
8069
8070        // If there are more arguments, they should be after a comma.
8071        if (!isComma(arg))
8072            return 0;
8073
8074        // Skip the comma and move on to the next argument.
8075        arg = functionArgs->next();
8076    }
8077
8078    return imageSet.release();
8079}
8080#endif
8081
8082class TransformOperationInfo {
8083public:
8084    TransformOperationInfo(const CSSParserString& name)
8085        : m_type(WebKitCSSTransformValue::UnknownTransformOperation)
8086        , m_argCount(1)
8087        , m_allowSingleArgument(false)
8088        , m_unit(CSSParser::FUnknown)
8089    {
8090        const UChar* characters;
8091        unsigned nameLength = name.length();
8092
8093        const unsigned longestNameLength = 12;
8094        UChar characterBuffer[longestNameLength];
8095        if (name.is8Bit()) {
8096            unsigned length = std::min(longestNameLength, nameLength);
8097            const LChar* characters8 = name.characters8();
8098            for (unsigned i = 0; i < length; ++i)
8099                characterBuffer[i] = characters8[i];
8100            characters = characterBuffer;
8101        } else
8102            characters = name.characters16();
8103
8104        switch (nameLength) {
8105        case 5:
8106            // Valid name: skew(.
8107            if (((characters[0] == 's') || (characters[0] == 'S'))
8108                & ((characters[1] == 'k') || (characters[1] == 'K'))
8109                & ((characters[2] == 'e') || (characters[2] == 'E'))
8110                & ((characters[3] == 'w') || (characters[3] == 'W'))
8111                & (characters[4] == '(')) {
8112                m_unit = CSSParser::FAngle;
8113                m_type = WebKitCSSTransformValue::SkewTransformOperation;
8114                m_allowSingleArgument = true;
8115                m_argCount = 3;
8116            }
8117            break;
8118        case 6:
8119            // Valid names: skewx(, skewy(, scale(.
8120            if ((characters[1] == 'c') || (characters[1] == 'C')) {
8121                if (((characters[0] == 's') || (characters[0] == 'S'))
8122                    & ((characters[2] == 'a') || (characters[2] == 'A'))
8123                    & ((characters[3] == 'l') || (characters[3] == 'L'))
8124                    & ((characters[4] == 'e') || (characters[4] == 'E'))
8125                    & (characters[5] == '(')) {
8126                    m_unit = CSSParser::FNumber;
8127                    m_type = WebKitCSSTransformValue::ScaleTransformOperation;
8128                    m_allowSingleArgument = true;
8129                    m_argCount = 3;
8130                }
8131            } else if (((characters[0] == 's') || (characters[0] == 'S'))
8132                       & ((characters[1] == 'k') || (characters[1] == 'K'))
8133                       & ((characters[2] == 'e') || (characters[2] == 'E'))
8134                       & ((characters[3] == 'w') || (characters[3] == 'W'))
8135                       & (characters[5] == '(')) {
8136                if ((characters[4] == 'x') || (characters[4] == 'X')) {
8137                    m_unit = CSSParser::FAngle;
8138                    m_type = WebKitCSSTransformValue::SkewXTransformOperation;
8139                } else if ((characters[4] == 'y') || (characters[4] == 'Y')) {
8140                    m_unit = CSSParser::FAngle;
8141                    m_type = WebKitCSSTransformValue::SkewYTransformOperation;
8142                }
8143            }
8144            break;
8145        case 7:
8146            // Valid names: matrix(, rotate(, scalex(, scaley(, scalez(.
8147            if ((characters[0] == 'm') || (characters[0] == 'M')) {
8148                if (((characters[1] == 'a') || (characters[1] == 'A'))
8149                    & ((characters[2] == 't') || (characters[2] == 'T'))
8150                    & ((characters[3] == 'r') || (characters[3] == 'R'))
8151                    & ((characters[4] == 'i') || (characters[4] == 'I'))
8152                    & ((characters[5] == 'x') || (characters[5] == 'X'))
8153                    & (characters[6] == '(')) {
8154                    m_unit = CSSParser::FNumber;
8155                    m_type = WebKitCSSTransformValue::MatrixTransformOperation;
8156                    m_argCount = 11;
8157                }
8158            } else if ((characters[0] == 'r') || (characters[0] == 'R')) {
8159                if (((characters[1] == 'o') || (characters[1] == 'O'))
8160                    & ((characters[2] == 't') || (characters[2] == 'T'))
8161                    & ((characters[3] == 'a') || (characters[3] == 'A'))
8162                    & ((characters[4] == 't') || (characters[4] == 'T'))
8163                    & ((characters[5] == 'e') || (characters[5] == 'E'))
8164                    & (characters[6] == '(')) {
8165                    m_unit = CSSParser::FAngle;
8166                    m_type = WebKitCSSTransformValue::RotateTransformOperation;
8167                }
8168            } else if (((characters[0] == 's') || (characters[0] == 'S'))
8169                       & ((characters[1] == 'c') || (characters[1] == 'C'))
8170                       & ((characters[2] == 'a') || (characters[2] == 'A'))
8171                       & ((characters[3] == 'l') || (characters[3] == 'L'))
8172                       & ((characters[4] == 'e') || (characters[4] == 'E'))
8173                       & (characters[6] == '(')) {
8174                if ((characters[5] == 'x') || (characters[5] == 'X')) {
8175                    m_unit = CSSParser::FNumber;
8176                    m_type = WebKitCSSTransformValue::ScaleXTransformOperation;
8177                } else if ((characters[5] == 'y') || (characters[5] == 'Y')) {
8178                    m_unit = CSSParser::FNumber;
8179                    m_type = WebKitCSSTransformValue::ScaleYTransformOperation;
8180                } else if ((characters[5] == 'z') || (characters[5] == 'Z')) {
8181                    m_unit = CSSParser::FNumber;
8182                    m_type = WebKitCSSTransformValue::ScaleZTransformOperation;
8183                }
8184            }
8185            break;
8186        case 8:
8187            // Valid names: rotatex(, rotatey(, rotatez(, scale3d(.
8188            if ((characters[0] == 's') || (characters[0] == 'S')) {
8189                if (((characters[1] == 'c') || (characters[1] == 'C'))
8190                    & ((characters[2] == 'a') || (characters[2] == 'A'))
8191                    & ((characters[3] == 'l') || (characters[3] == 'L'))
8192                    & ((characters[4] == 'e') || (characters[4] == 'E'))
8193                    & (characters[5] == '3')
8194                    & ((characters[6] == 'd') || (characters[6] == 'D'))
8195                    & (characters[7] == '(')) {
8196                    m_unit = CSSParser::FNumber;
8197                    m_type = WebKitCSSTransformValue::Scale3DTransformOperation;
8198                    m_argCount = 5;
8199                }
8200            } else if (((characters[0] == 'r') || (characters[0] == 'R'))
8201                       & ((characters[1] == 'o') || (characters[1] == 'O'))
8202                       & ((characters[2] == 't') || (characters[2] == 'T'))
8203                       & ((characters[3] == 'a') || (characters[3] == 'A'))
8204                       & ((characters[4] == 't') || (characters[4] == 'T'))
8205                       & ((characters[5] == 'e') || (characters[5] == 'E'))
8206                       & (characters[7] == '(')) {
8207                if ((characters[6] == 'x') || (characters[6] == 'X')) {
8208                    m_unit = CSSParser::FAngle;
8209                    m_type = WebKitCSSTransformValue::RotateXTransformOperation;
8210                } else if ((characters[6] == 'y') || (characters[6] == 'Y')) {
8211                    m_unit = CSSParser::FAngle;
8212                    m_type = WebKitCSSTransformValue::RotateYTransformOperation;
8213                } else if ((characters[6] == 'z') || (characters[6] == 'Z')) {
8214                    m_unit = CSSParser::FAngle;
8215                    m_type = WebKitCSSTransformValue::RotateZTransformOperation;
8216                }
8217            }
8218            break;
8219        case 9:
8220            // Valid names: matrix3d(, rotate3d(.
8221            if ((characters[0] == 'm') || (characters[0] == 'M')) {
8222                if (((characters[1] == 'a') || (characters[1] == 'A'))
8223                    & ((characters[2] == 't') || (characters[2] == 'T'))
8224                    & ((characters[3] == 'r') || (characters[3] == 'R'))
8225                    & ((characters[4] == 'i') || (characters[4] == 'I'))
8226                    & ((characters[5] == 'x') || (characters[5] == 'X'))
8227                    & (characters[6] == '3')
8228                    & ((characters[7] == 'd') || (characters[7] == 'D'))
8229                    & (characters[8] == '(')) {
8230                    m_unit = CSSParser::FNumber;
8231                    m_type = WebKitCSSTransformValue::Matrix3DTransformOperation;
8232                    m_argCount = 31;
8233                }
8234            } else if (((characters[0] == 'r') || (characters[0] == 'R'))
8235                       & ((characters[1] == 'o') || (characters[1] == 'O'))
8236                       & ((characters[2] == 't') || (characters[2] == 'T'))
8237                       & ((characters[3] == 'a') || (characters[3] == 'A'))
8238                       & ((characters[4] == 't') || (characters[4] == 'T'))
8239                       & ((characters[5] == 'e') || (characters[5] == 'E'))
8240                       & (characters[6] == '3')
8241                       & ((characters[7] == 'd') || (characters[7] == 'D'))
8242                       & (characters[8] == '(')) {
8243                m_unit = CSSParser::FNumber;
8244                m_type = WebKitCSSTransformValue::Rotate3DTransformOperation;
8245                m_argCount = 7;
8246            }
8247            break;
8248        case 10:
8249            // Valid name: translate(.
8250            if (((characters[0] == 't') || (characters[0] == 'T'))
8251                & ((characters[1] == 'r') || (characters[1] == 'R'))
8252                & ((characters[2] == 'a') || (characters[2] == 'A'))
8253                & ((characters[3] == 'n') || (characters[3] == 'N'))
8254                & ((characters[4] == 's') || (characters[4] == 'S'))
8255                & ((characters[5] == 'l') || (characters[5] == 'L'))
8256                & ((characters[6] == 'a') || (characters[6] == 'A'))
8257                & ((characters[7] == 't') || (characters[7] == 'T'))
8258                & ((characters[8] == 'e') || (characters[8] == 'E'))
8259                & (characters[9] == '(')) {
8260                m_unit = CSSParser::FLength | CSSParser::FPercent;
8261                m_type = WebKitCSSTransformValue::TranslateTransformOperation;
8262                m_allowSingleArgument = true;
8263                m_argCount = 3;
8264            }
8265            break;
8266        case 11:
8267            // Valid names: translatex(, translatey(, translatez(.
8268            if (((characters[0] == 't') || (characters[0] == 'T'))
8269                & ((characters[1] == 'r') || (characters[1] == 'R'))
8270                & ((characters[2] == 'a') || (characters[2] == 'A'))
8271                & ((characters[3] == 'n') || (characters[3] == 'N'))
8272                & ((characters[4] == 's') || (characters[4] == 'S'))
8273                & ((characters[5] == 'l') || (characters[5] == 'L'))
8274                & ((characters[6] == 'a') || (characters[6] == 'A'))
8275                & ((characters[7] == 't') || (characters[7] == 'T'))
8276                & ((characters[8] == 'e') || (characters[8] == 'E'))
8277                & (characters[10] == '(')) {
8278                if ((characters[9] == 'x') || (characters[9] == 'X')) {
8279                    m_unit = CSSParser::FLength | CSSParser::FPercent;
8280                    m_type = WebKitCSSTransformValue::TranslateXTransformOperation;
8281                } else if ((characters[9] == 'y') || (characters[9] == 'Y')) {
8282                    m_unit = CSSParser::FLength | CSSParser::FPercent;
8283                    m_type = WebKitCSSTransformValue::TranslateYTransformOperation;
8284                } else if ((characters[9] == 'z') || (characters[9] == 'Z')) {
8285                    m_unit = CSSParser::FLength | CSSParser::FPercent;
8286                    m_type = WebKitCSSTransformValue::TranslateZTransformOperation;
8287                }
8288            }
8289            break;
8290        case 12:
8291            // Valid names: perspective(, translate3d(.
8292            if ((characters[0] == 'p') || (characters[0] == 'P')) {
8293                if (((characters[1] == 'e') || (characters[1] == 'E'))
8294                    & ((characters[2] == 'r') || (characters[2] == 'R'))
8295                    & ((characters[3] == 's') || (characters[3] == 'S'))
8296                    & ((characters[4] == 'p') || (characters[4] == 'P'))
8297                    & ((characters[5] == 'e') || (characters[5] == 'E'))
8298                    & ((characters[6] == 'c') || (characters[6] == 'C'))
8299                    & ((characters[7] == 't') || (characters[7] == 'T'))
8300                    & ((characters[8] == 'i') || (characters[8] == 'I'))
8301                    & ((characters[9] == 'v') || (characters[9] == 'V'))
8302                    & ((characters[10] == 'e') || (characters[10] == 'E'))
8303                    & (characters[11] == '(')) {
8304                    m_unit = CSSParser::FNumber;
8305                    m_type = WebKitCSSTransformValue::PerspectiveTransformOperation;
8306                }
8307            } else if (((characters[0] == 't') || (characters[0] == 'T'))
8308                       & ((characters[1] == 'r') || (characters[1] == 'R'))
8309                       & ((characters[2] == 'a') || (characters[2] == 'A'))
8310                       & ((characters[3] == 'n') || (characters[3] == 'N'))
8311                       & ((characters[4] == 's') || (characters[4] == 'S'))
8312                       & ((characters[5] == 'l') || (characters[5] == 'L'))
8313                       & ((characters[6] == 'a') || (characters[6] == 'A'))
8314                       & ((characters[7] == 't') || (characters[7] == 'T'))
8315                       & ((characters[8] == 'e') || (characters[8] == 'E'))
8316                       & (characters[9] == '3')
8317                       & ((characters[10] == 'd') || (characters[10] == 'D'))
8318                       & (characters[11] == '(')) {
8319                m_unit = CSSParser::FLength | CSSParser::FPercent;
8320                m_type = WebKitCSSTransformValue::Translate3DTransformOperation;
8321                m_argCount = 5;
8322            }
8323            break;
8324        } // end switch ()
8325    }
8326
8327    WebKitCSSTransformValue::TransformOperationType type() const { return m_type; }
8328    unsigned argCount() const { return m_argCount; }
8329    CSSParser::Units unit() const { return m_unit; }
8330
8331    bool unknown() const { return m_type == WebKitCSSTransformValue::UnknownTransformOperation; }
8332    bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
8333
8334private:
8335    WebKitCSSTransformValue::TransformOperationType m_type;
8336    unsigned m_argCount;
8337    bool m_allowSingleArgument;
8338    CSSParser::Units m_unit;
8339};
8340
8341PassRefPtr<CSSValueList> CSSParser::parseTransform()
8342{
8343    if (!m_valueList)
8344        return 0;
8345
8346    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8347    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
8348        RefPtr<CSSValue> parsedTransformValue = parseTransformValue(value);
8349        if (!parsedTransformValue)
8350            return 0;
8351
8352        list->append(parsedTransformValue.release());
8353    }
8354
8355    return list.release();
8356}
8357
8358PassRefPtr<CSSValue> CSSParser::parseTransformValue(CSSParserValue *value)
8359{
8360    if (value->unit != CSSParserValue::Function || !value->function)
8361        return 0;
8362
8363    // Every primitive requires at least one argument.
8364    CSSParserValueList* args = value->function->args.get();
8365    if (!args)
8366        return 0;
8367
8368    // See if the specified primitive is one we understand.
8369    TransformOperationInfo info(value->function->name);
8370    if (info.unknown())
8371        return 0;
8372
8373    if (!info.hasCorrectArgCount(args->size()))
8374        return 0;
8375
8376    // The transform is a list of functional primitives that specify transform operations.
8377    // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation.
8378
8379    // Create the new WebKitCSSTransformValue for this operation and add it to our list.
8380    RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(info.type());
8381
8382    // Snag our values.
8383    CSSParserValue* a = args->current();
8384    unsigned argNumber = 0;
8385    while (a) {
8386        CSSParser::Units unit = info.unit();
8387
8388        if (info.type() == WebKitCSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
8389            // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
8390            if (!validUnit(a, FAngle, CSSStrictMode))
8391                return 0;
8392        } else if (info.type() == WebKitCSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
8393            // 3rd param of translate3d() cannot be a percentage
8394            if (!validUnit(a, FLength, CSSStrictMode))
8395                return 0;
8396        } else if (info.type() == WebKitCSSTransformValue::TranslateZTransformOperation && !argNumber) {
8397            // 1st param of translateZ() cannot be a percentage
8398            if (!validUnit(a, FLength, CSSStrictMode))
8399                return 0;
8400        } else if (info.type() == WebKitCSSTransformValue::PerspectiveTransformOperation && !argNumber) {
8401            // 1st param of perspective() must be a non-negative number (deprecated) or length.
8402            if (!validUnit(a, FNumber | FLength | FNonNeg, CSSStrictMode))
8403                return 0;
8404        } else if (!validUnit(a, unit, CSSStrictMode))
8405            return 0;
8406
8407        // Add the value to the current transform operation.
8408        transformValue->append(createPrimitiveNumericValue(a));
8409
8410        a = args->next();
8411        if (!a)
8412            break;
8413        if (a->unit != CSSParserValue::Operator || a->iValue != ',')
8414            return 0;
8415        a = args->next();
8416
8417        argNumber++;
8418    }
8419
8420    return transformValue.release();
8421}
8422
8423bool CSSParser::isBlendMode(int ident)
8424{
8425    return (ident >= CSSValueMultiply && ident <= CSSValueLuminosity)
8426        || ident == CSSValueNormal
8427        || ident == CSSValueOverlay;
8428}
8429
8430bool CSSParser::isCompositeOperator(int ident)
8431{
8432    // FIXME: Add CSSValueDestination and CSSValueLighter when the Compositing spec updates.
8433    return ident >= CSSValueClear && ident <= CSSValueXor;
8434}
8435
8436#if ENABLE(CSS_FILTERS)
8437
8438static void filterInfoForName(const CSSParserString& name, WebKitCSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
8439{
8440    if (equalIgnoringCase(name, "grayscale("))
8441        filterType = WebKitCSSFilterValue::GrayscaleFilterOperation;
8442    else if (equalIgnoringCase(name, "sepia("))
8443        filterType = WebKitCSSFilterValue::SepiaFilterOperation;
8444    else if (equalIgnoringCase(name, "saturate("))
8445        filterType = WebKitCSSFilterValue::SaturateFilterOperation;
8446    else if (equalIgnoringCase(name, "hue-rotate("))
8447        filterType = WebKitCSSFilterValue::HueRotateFilterOperation;
8448    else if (equalIgnoringCase(name, "invert("))
8449        filterType = WebKitCSSFilterValue::InvertFilterOperation;
8450    else if (equalIgnoringCase(name, "opacity("))
8451        filterType = WebKitCSSFilterValue::OpacityFilterOperation;
8452    else if (equalIgnoringCase(name, "brightness("))
8453        filterType = WebKitCSSFilterValue::BrightnessFilterOperation;
8454    else if (equalIgnoringCase(name, "contrast("))
8455        filterType = WebKitCSSFilterValue::ContrastFilterOperation;
8456    else if (equalIgnoringCase(name, "blur("))
8457        filterType = WebKitCSSFilterValue::BlurFilterOperation;
8458    else if (equalIgnoringCase(name, "drop-shadow(")) {
8459        filterType = WebKitCSSFilterValue::DropShadowFilterOperation;
8460        maximumArgumentCount = 4;  // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
8461    }
8462#if ENABLE(CSS_SHADERS)
8463    else if (equalIgnoringCase(name, "custom("))
8464        filterType = WebKitCSSFilterValue::CustomFilterOperation;
8465#endif
8466}
8467
8468#if ENABLE(CSS_SHADERS)
8469static bool acceptCommaOperator(CSSParserValueList* argsList)
8470{
8471    if (CSSParserValue* arg = argsList->current()) {
8472        if (!isComma(arg))
8473            return false;
8474        argsList->next();
8475    }
8476    return true;
8477}
8478
8479PassRefPtr<WebKitCSSArrayFunctionValue> CSSParser::parseCustomFilterArrayFunction(CSSParserValue* value)
8480{
8481    ASSERT(value->unit == CSSParserValue::Function && value->function);
8482
8483    if (!equalIgnoringCase(value->function->name, "array("))
8484        return 0;
8485
8486    CSSParserValueList* arrayArgsParserValueList = value->function->args.get();
8487    if (!arrayArgsParserValueList || !arrayArgsParserValueList->size())
8488        return 0;
8489
8490    // array() values are comma separated.
8491    RefPtr<WebKitCSSArrayFunctionValue> arrayFunction = WebKitCSSArrayFunctionValue::create();
8492    while (true) {
8493        // We parse pairs <Value, Comma> at each step.
8494        CSSParserValue* currentParserValue = arrayArgsParserValueList->current();
8495        if (!currentParserValue || !validUnit(currentParserValue, FNumber, CSSStrictMode))
8496            return 0;
8497
8498        RefPtr<CSSValue> arrayValue = cssValuePool().createValue(currentParserValue->fValue, CSSPrimitiveValue::CSS_NUMBER);
8499        arrayFunction->append(arrayValue.release());
8500
8501        CSSParserValue* nextParserValue = arrayArgsParserValueList->next();
8502        if (!nextParserValue)
8503            break;
8504
8505        if (!isComma(nextParserValue))
8506            return 0;
8507
8508        arrayArgsParserValueList->next();
8509    }
8510
8511    return arrayFunction;
8512}
8513
8514PassRefPtr<WebKitCSSMatFunctionValue> CSSParser::parseMatValue(CSSParserValue* value)
8515{
8516    if (value->unit != CSSParserValue::Function || !value->function)
8517        return 0;
8518
8519    unsigned numberOfValues = 0;
8520    if (equalIgnoringCase(value->function->name, "mat2("))
8521        numberOfValues = 4;
8522    else if (equalIgnoringCase(value->function->name, "mat3("))
8523        numberOfValues = 9;
8524    else if (equalIgnoringCase(value->function->name, "mat4("))
8525        numberOfValues = 16;
8526    else
8527        return 0;
8528
8529    CSSParserValueList* args = value->function->args.get();
8530    if (!args || args->size() != (numberOfValues * 2 - 1))
8531        return 0;
8532
8533    RefPtr<WebKitCSSMatFunctionValue> matValueList = WebKitCSSMatFunctionValue::create();
8534    CSSParserValue* arg = args->current();
8535    while (arg) {
8536        if (!validUnit(arg, FNumber, CSSStrictMode))
8537            return 0;
8538        matValueList->append(cssValuePool().createValue(arg->fValue, CSSPrimitiveValue::CSS_NUMBER));
8539        arg = args->next();
8540
8541        if (!arg)
8542            break;
8543
8544        if (!isComma(arg))
8545            return 0;
8546
8547        arg = args->next();
8548    }
8549
8550    if (!matValueList || matValueList->length() != numberOfValues)
8551        return 0;
8552
8553    return matValueList.release();
8554}
8555
8556PassRefPtr<WebKitCSSMixFunctionValue> CSSParser::parseMixFunction(CSSParserValue* value)
8557{
8558    ASSERT(value->unit == CSSParserValue::Function && value->function);
8559
8560    if (!equalIgnoringCase(value->function->name, "mix("))
8561        return 0;
8562
8563    CSSParserValueList* argsList = value->function->args.get();
8564    if (!argsList)
8565        return 0;
8566
8567    unsigned numArgs = argsList->size();
8568    if (numArgs < 1 || numArgs > 3)
8569        return 0;
8570
8571    RefPtr<WebKitCSSMixFunctionValue> mixFunction = WebKitCSSMixFunctionValue::create();
8572
8573    bool hasBlendMode = false;
8574    bool hasAlphaCompositing = false;
8575    CSSParserValue* arg;
8576    while ((arg = argsList->current())) {
8577        RefPtr<CSSValue> value;
8578
8579        unsigned argNumber = argsList->currentIndex();
8580        if (!argNumber) {
8581            if (arg->unit == CSSPrimitiveValue::CSS_URI) {
8582                KURL shaderURL = completeURL(arg->string);
8583                value = WebKitCSSShaderValue::create(shaderURL.string());
8584            }
8585        } else if (argNumber == 1 || argNumber == 2) {
8586            if (!hasBlendMode && isBlendMode(arg->id)) {
8587                hasBlendMode = true;
8588                value = cssValuePool().createIdentifierValue(arg->id);
8589            } else if (!hasAlphaCompositing && isCompositeOperator(arg->id)) {
8590                hasAlphaCompositing = true;
8591                value = cssValuePool().createIdentifierValue(arg->id);
8592            }
8593        }
8594
8595        if (!value)
8596            return 0;
8597
8598        mixFunction->append(value.release());
8599
8600        arg = argsList->next();
8601    }
8602
8603    return mixFunction;
8604}
8605
8606PassRefPtr<CSSValueList> CSSParser::parseCustomFilterParameters(CSSParserValueList* argsList)
8607{
8608    //
8609    // params:      [<param-def>[,<param-def>*]]
8610    // param-def:   <param-name>wsp<param-value>
8611    // param-name:  <ident>
8612    // param-value: true|false[wsp+true|false]{0-3} |
8613    //              <number>[wsp+<number>]{0-3} |
8614    //              <array> |
8615    //              <transform> |
8616    //              <texture(<uri>)>
8617    // array: 'array('<number>[wsp<number>]*')'
8618    // css-3d-transform: <transform-function>;[<transform-function>]*
8619    // transform:   <css-3d-transform> | <mat>
8620    // mat:         'mat2('<number>(,<number>){3}')' |
8621    //              'mat3('<number>(,<number>){8}')' |
8622    //              'mat4('<number>(,<number>){15}')' )
8623    //
8624
8625    RefPtr<CSSValueList> paramList = CSSValueList::createCommaSeparated();
8626
8627    while (CSSParserValue* arg = argsList->current()) {
8628        if (arg->unit != CSSPrimitiveValue::CSS_IDENT)
8629            return 0;
8630
8631        RefPtr<CSSValueList> parameter = CSSValueList::createSpaceSeparated();
8632        parameter->append(createPrimitiveStringValue(arg));
8633
8634        arg = argsList->next();
8635        if (!arg)
8636            return 0;
8637
8638        RefPtr<CSSValue> parameterValue;
8639
8640        if (arg->unit == CSSParserValue::Function && arg->function) {
8641            // FIXME: Implement parsing for the other parameter types.
8642            // textures: https://bugs.webkit.org/show_bug.cgi?id=71442
8643            if (equalIgnoringCase(arg->function->name, "array(")) {
8644                parameterValue = parseCustomFilterArrayFunction(arg);
8645                // This parsing step only consumes function arguments,
8646                // argsList is therefore moved forward explicitely.
8647                argsList->next();
8648            } else {
8649                // Parse mat2, mat3 and mat4 functions.
8650                parameterValue = parseMatValue(arg);
8651                if (!parameterValue && arg)
8652                    parameterValue = parseCustomFilterTransform(argsList);
8653                else if (parameterValue)
8654                    argsList->next();
8655            }
8656        } else if (validUnit(arg, FNumber, CSSStrictMode)) {
8657            RefPtr<CSSValueList> paramValueList = CSSValueList::createSpaceSeparated();
8658            while (arg) {
8659                // If we hit a comma, it means that we finished this parameter's values.
8660                if (isComma(arg))
8661                    break;
8662                if (!validUnit(arg, FNumber, CSSStrictMode))
8663                    return 0;
8664                paramValueList->append(cssValuePool().createValue(arg->fValue, CSSPrimitiveValue::CSS_NUMBER));
8665                arg = argsList->next();
8666            }
8667            if (!paramValueList->length() || paramValueList->length() > 4)
8668                return 0;
8669            parameterValue = paramValueList.release();
8670        }
8671        if (!parameterValue && arg) {
8672            // All parameter values need to be CSSValueLists.
8673            RefPtr<CSSValueList> paramValueList = CSSValueList::createSpaceSeparated();
8674            RefPtr<CSSPrimitiveValue> colorValue = parseColor(arg);
8675            if (!colorValue)
8676                return 0;
8677            paramValueList->append(colorValue.release());
8678            parameterValue = paramValueList.release();
8679            arg = argsList->next();
8680        }
8681
8682        if (!parameterValue || !acceptCommaOperator(argsList))
8683            return 0;
8684
8685        parameter->append(parameterValue.release());
8686        paramList->append(parameter.release());
8687    }
8688
8689    return paramList;
8690}
8691
8692PassRefPtr<WebKitCSSFilterValue> CSSParser::parseCustomFilterFunctionWithAtRuleReferenceSyntax(CSSParserValue* value)
8693{
8694    //
8695    // Custom filter function "at-rule reference" syntax:
8696    //
8697    // custom(<filter-name>wsp[,wsp<params>])
8698    //
8699    // filter-name: <filter-name>
8700    // params: See the comment in CSSParser::parseCustomFilterParameters.
8701    //
8702
8703    ASSERT(value->function);
8704
8705    CSSParserValueList* argsList = value->function->args.get();
8706    if (!argsList || !argsList->size())
8707        return 0;
8708
8709    // 1. Parse the filter name.
8710    CSSParserValue* arg = argsList->current();
8711    if (arg->unit != CSSPrimitiveValue::CSS_IDENT)
8712        return 0;
8713
8714    RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::CustomFilterOperation);
8715
8716    RefPtr<CSSValue> filterName = createPrimitiveStringValue(arg);
8717    filterValue->append(filterName);
8718    argsList->next();
8719
8720    if (!acceptCommaOperator(argsList))
8721        return 0;
8722
8723    // 2. Parse the parameters.
8724    RefPtr<CSSValueList> paramList = parseCustomFilterParameters(argsList);
8725    if (!paramList)
8726        return 0;
8727
8728    if (paramList->length())
8729        filterValue->append(paramList.release());
8730
8731    return filterValue;
8732}
8733
8734// FIXME: The custom filters "inline" syntax is deprecated. We will remove it eventually.
8735PassRefPtr<WebKitCSSFilterValue> CSSParser::parseCustomFilterFunctionWithInlineSyntax(CSSParserValue* value)
8736{
8737    //
8738    // Custom filter function "inline" syntax:
8739    //
8740    // custom(<vertex-shader>[wsp<fragment-shader>][,<vertex-mesh>][,<params>])
8741    //
8742    // vertexShader:    <uri> | none
8743    // fragmentShader:  <uri> | none | mix(<uri> [ <blend-mode> || <alpha-compositing> ]?)
8744    //
8745    // blend-mode: normal | multiply | screen | overlay | darken | lighten | color-dodge |
8746    //             color-burn | hard-light | soft-light | difference | exclusion | hue |
8747    //             saturation | color | luminosity
8748    // alpha-compositing: clear | src | dst | src-over | dst-over | src-in | dst-in |
8749    //                    src-out | dst-out | src-atop | dst-atop | xor | plus
8750    //
8751    // vertexMesh:  +<integer>{1,2}[wsp<box>][wsp'detached']
8752    // box: filter-box | border-box | padding-box | content-box
8753    //
8754    // params: See the comment in CSSParser::parseCustomFilterParameters.
8755    //
8756
8757    ASSERT(value->function);
8758
8759    CSSParserValueList* argsList = value->function->args.get();
8760    if (!argsList)
8761        return 0;
8762
8763    RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::CustomFilterOperation);
8764
8765    // 1. Parse the shader URLs: <vertex-shader>[wsp<fragment-shader>]
8766    RefPtr<CSSValueList> shadersList = CSSValueList::createSpaceSeparated();
8767    bool hadAtLeastOneCustomShader = false;
8768    CSSParserValue* arg;
8769    while ((arg = argsList->current())) {
8770        RefPtr<CSSValue> value;
8771        if (arg->id == CSSValueNone)
8772            value = cssValuePool().createIdentifierValue(CSSValueNone);
8773        else if (arg->unit == CSSPrimitiveValue::CSS_URI) {
8774            KURL shaderURL = completeURL(arg->string);
8775            value = WebKitCSSShaderValue::create(shaderURL.string());
8776            hadAtLeastOneCustomShader = true;
8777        } else if (argsList->currentIndex() == 1 && arg->unit == CSSParserValue::Function) {
8778            if (!(value = parseMixFunction(arg)))
8779                return 0;
8780            hadAtLeastOneCustomShader = true;
8781        }
8782
8783        if (!value)
8784            break;
8785        shadersList->append(value.release());
8786        argsList->next();
8787    }
8788
8789    if (!shadersList->length() || !hadAtLeastOneCustomShader || shadersList->length() > 2 || !acceptCommaOperator(argsList))
8790        return 0;
8791
8792    filterValue->append(shadersList.release());
8793
8794    // 2. Parse the mesh size <vertex-mesh>
8795    RefPtr<CSSValueList> meshSizeList = CSSValueList::createSpaceSeparated();
8796
8797    while ((arg = argsList->current())) {
8798        if (!validUnit(arg, FInteger | FNonNeg, CSSStrictMode))
8799            break;
8800        int integerValue = clampToInteger(arg->fValue);
8801        // According to the specification we can only accept positive non-zero values.
8802        if (integerValue < 1)
8803            return 0;
8804        meshSizeList->append(cssValuePool().createValue(integerValue, CSSPrimitiveValue::CSS_NUMBER));
8805        argsList->next();
8806    }
8807
8808    if (meshSizeList->length() > 2)
8809        return 0;
8810
8811    // FIXME: For legacy content, we accept the mesh box types. We don't do anything else with them.
8812    // Eventually, we'll remove them completely.
8813    // https://bugs.webkit.org/show_bug.cgi?id=103778
8814    if ((arg = argsList->current()) && (arg->id == CSSValueBorderBox || arg->id == CSSValuePaddingBox
8815        || arg->id == CSSValueContentBox || arg->id == CSSValueFilterBox))
8816        argsList->next();
8817
8818    if ((arg = argsList->current()) && arg->id == CSSValueDetached) {
8819        meshSizeList->append(cssValuePool().createIdentifierValue(arg->id));
8820        argsList->next();
8821    }
8822
8823    if (meshSizeList->length()) {
8824        if (!acceptCommaOperator(argsList))
8825            return 0;
8826        filterValue->append(meshSizeList.release());
8827    }
8828
8829    // 3. Parse the parameters.
8830    RefPtr<CSSValueList> paramList = parseCustomFilterParameters(argsList);
8831    if (!paramList)
8832        return 0;
8833
8834    if (paramList->length())
8835        filterValue->append(paramList.release());
8836
8837    return filterValue;
8838}
8839
8840PassRefPtr<WebKitCSSFilterValue> CSSParser::parseCustomFilterFunction(CSSParserValue* value)
8841{
8842    ASSERT(value->function);
8843
8844    // Look ahead to determine which syntax the custom function is using.
8845    // Both the at-rule reference syntax and the inline syntax require at least one argument.
8846    CSSParserValueList* argsList = value->function->args.get();
8847    if (!argsList || !argsList->size())
8848        return 0;
8849
8850    // The at-rule reference syntax expects a single ident or an ident followed by a comma.
8851    // e.g. custom(my-filter) or custom(my-filter, ...)
8852    // In contrast, when the inline syntax starts with an ident like "none", it expects a uri or a mix function next.
8853    // e.g. custom(none url(...)) or custom(none mix(...)
8854    bool isAtRuleReferenceSyntax = argsList->valueAt(0)->unit == CSSPrimitiveValue::CSS_IDENT
8855        && (argsList->size() == 1 || isComma(argsList->valueAt(1)));
8856    return isAtRuleReferenceSyntax ? parseCustomFilterFunctionWithAtRuleReferenceSyntax(value) : parseCustomFilterFunctionWithInlineSyntax(value);
8857}
8858
8859PassRefPtr<CSSValueList> CSSParser::parseCustomFilterTransform(CSSParserValueList* valueList)
8860{
8861    if (!valueList)
8862        return 0;
8863
8864    // CSS Shaders' custom() transforms are space separated and comma terminated.
8865    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
8866    for (CSSParserValue* value = valueList->current(); value; value = valueList->next()) {
8867        if (isComma(value))
8868            break;
8869
8870        RefPtr<CSSValue> parsedTransformValue = parseTransformValue(value);
8871        if (!parsedTransformValue)
8872            return 0;
8873
8874        list->append(parsedTransformValue.release());
8875    }
8876
8877    return list.release();
8878}
8879
8880PassRefPtr<WebKitCSSShaderValue> CSSParser::parseFilterRuleSrcUriAndFormat(CSSParserValueList* valueList)
8881{
8882    CSSParserValue* value = valueList->current();
8883    ASSERT(value && value->unit == CSSPrimitiveValue::CSS_URI);
8884    RefPtr<WebKitCSSShaderValue> shaderValue = WebKitCSSShaderValue::create(completeURL(value->string));
8885
8886    value = valueList->next();
8887    if (value && value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "format(")) {
8888        CSSParserValueList* args = value->function->args.get();
8889        if (!args || args->size() != 1)
8890            return 0;
8891
8892        CSSParserValue* arg = args->current();
8893        if (arg->unit != CSSPrimitiveValue::CSS_STRING)
8894            return 0;
8895
8896        shaderValue->setFormat(arg->string);
8897        valueList->next();
8898    }
8899
8900    return shaderValue.release();
8901}
8902
8903bool CSSParser::parseFilterRuleSrc()
8904{
8905    RefPtr<CSSValueList> srcList = CSSValueList::createCommaSeparated();
8906
8907    CSSParserValue* value = m_valueList->current();
8908    while (value) {
8909        if (value->unit != CSSPrimitiveValue::CSS_URI)
8910            return false;
8911
8912        RefPtr<WebKitCSSShaderValue> shaderValue = parseFilterRuleSrcUriAndFormat(m_valueList.get());
8913        if (!shaderValue)
8914            return false;
8915        srcList->append(shaderValue.release());
8916
8917        if (!acceptCommaOperator(m_valueList.get()))
8918            return false;
8919
8920        value = m_valueList->current();
8921    }
8922
8923    if (!srcList->length())
8924        return false;
8925
8926    addProperty(CSSPropertySrc, srcList.release(), m_important);
8927    return true;
8928}
8929
8930bool CSSParser::parseFilterRuleMix()
8931{
8932    if (m_valueList->size() > 2)
8933        return false;
8934
8935    RefPtr<CSSValueList> mixList = CSSValueList::createSpaceSeparated();
8936
8937    bool hasBlendMode = false;
8938    bool hasAlphaCompositing = false;
8939    CSSParserValue* value = m_valueList->current();
8940    while (value) {
8941        RefPtr<CSSValue> mixValue;
8942        if (!hasBlendMode && isBlendMode(value->id)) {
8943            hasBlendMode = true;
8944            mixValue = cssValuePool().createIdentifierValue(value->id);
8945        } else if (!hasAlphaCompositing && isCompositeOperator(value->id)) {
8946            hasAlphaCompositing = true;
8947            mixValue = cssValuePool().createIdentifierValue(value->id);
8948        }
8949
8950        if (!mixValue)
8951            return false;
8952
8953        mixList->append(mixValue.release());
8954        value = m_valueList->next();
8955    }
8956
8957    addProperty(CSSPropertyMix, mixList.release(), m_important);
8958    return true;
8959}
8960
8961bool CSSParser::parseGeometry(CSSPropertyID propId, CSSParserValue* value, bool important)
8962{
8963    ASSERT(propId == CSSPropertyGeometry);
8964
8965    // <geometry-shape> = grid(<integer>{1,2} || [ detached | attached ]?)
8966    if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "grid("))
8967        return false;
8968
8969    ASSERT(value->function->args);
8970
8971    // grid() function should have from 1 to 3 arguments.
8972    unsigned size = value->function->args->size();
8973    if (!size || size > 3)
8974        return false;
8975
8976    CSSParserValueList* gridParserValueList = value->function->args.get();
8977    CSSParserValue* gridParserValue = gridParserValueList->current();
8978    RefPtr<CSSValueList> geometryList = CSSValueList::createSpaceSeparated();
8979
8980    bool hasDimensions = false;
8981    bool hasConnectivity = false;
8982
8983    while (gridParserValue) {
8984        if (hasDimensions && hasConnectivity) {
8985            geometryList.release();
8986            return false;
8987        }
8988
8989        if (gridParserValue->id == CSSValueAttached || gridParserValue->id == CSSValueDetached) {
8990            hasConnectivity = true;
8991            geometryList->append(cssValuePool().createIdentifierValue(gridParserValue->id));
8992            gridParserValue = gridParserValueList->next();
8993        } else if (!hasDimensions && parseGridDimensions(gridParserValueList, geometryList)) {
8994            hasDimensions = true;
8995            gridParserValue = gridParserValueList->current();
8996        } else {
8997            geometryList.release();
8998            return false;
8999        }
9000    }
9001
9002    addProperty(propId, geometryList.release(), important);
9003    return hasDimensions;
9004}
9005
9006bool CSSParser::parseGridDimensions(CSSParserValueList* args, RefPtr<CSSValueList>& gridValueList)
9007{
9008    ASSERT(args);
9009
9010    // There must be at least one valid numeric value.
9011    CSSParserValue* arg = args->current();
9012    if (!arg || !validUnit(arg, FPositiveInteger))
9013        return false;
9014
9015    // A valid numeric value is parsed and then we move on.
9016    gridValueList->append(createPrimitiveNumericValue(arg));
9017    arg = args->next();
9018
9019    // If the next argument is not numeric, we are done parsing the grid dimensions.
9020    if (!arg || !validUnit(arg, FPositiveInteger))
9021        return true;
9022
9023    // Commit the second numeric value we found.
9024    gridValueList->append(createPrimitiveNumericValue(arg));
9025    args->next();
9026    return true;
9027}
9028
9029bool CSSParser::parseFilterRuleParameters()
9030{
9031    RefPtr<CSSValueList> paramsList = parseCustomFilterParameters(m_valueList.get());
9032    if (!paramsList)
9033        return false;
9034
9035    addProperty(CSSPropertyParameters, paramsList.release(), m_important);
9036    return true;
9037}
9038
9039StyleRuleBase* CSSParser::createFilterRule(const CSSParserString& filterName)
9040{
9041    RefPtr<StyleRuleFilter> rule = StyleRuleFilter::create(filterName);
9042    rule->setProperties(createStylePropertySet());
9043    clearProperties();
9044    StyleRuleFilter* result = rule.get();
9045    m_parsedRules.append(rule.release());
9046    processAndAddNewRuleToSourceTreeIfNeeded();
9047    return result;
9048}
9049
9050#endif // ENABLE(CSS_SHADERS)
9051
9052PassRefPtr<WebKitCSSFilterValue> CSSParser::parseBuiltinFilterArguments(CSSParserValueList* args, WebKitCSSFilterValue::FilterOperationType filterType)
9053{
9054    RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(filterType);
9055    ASSERT(args);
9056
9057    switch (filterType) {
9058    case WebKitCSSFilterValue::GrayscaleFilterOperation:
9059    case WebKitCSSFilterValue::SepiaFilterOperation:
9060    case WebKitCSSFilterValue::SaturateFilterOperation:
9061    case WebKitCSSFilterValue::InvertFilterOperation:
9062    case WebKitCSSFilterValue::OpacityFilterOperation:
9063    case WebKitCSSFilterValue::ContrastFilterOperation: {
9064        // One optional argument, 0-1 or 0%-100%, if missing use 100%.
9065        if (args->size() > 1)
9066            return 0;
9067
9068        if (args->size()) {
9069            CSSParserValue* value = args->current();
9070            if (!validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode))
9071                return 0;
9072
9073            double amount = value->fValue;
9074
9075            // Saturate and Contrast allow values over 100%.
9076            if (filterType != WebKitCSSFilterValue::SaturateFilterOperation
9077                && filterType != WebKitCSSFilterValue::ContrastFilterOperation) {
9078                double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
9079                if (amount > maxAllowed)
9080                    return 0;
9081            }
9082
9083            filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
9084        }
9085        break;
9086    }
9087    case WebKitCSSFilterValue::BrightnessFilterOperation: {
9088        // One optional argument, if missing use 100%.
9089        if (args->size() > 1)
9090            return 0;
9091
9092        if (args->size()) {
9093            CSSParserValue* value = args->current();
9094            if (!validUnit(value, FNumber | FPercent, CSSStrictMode))
9095                return 0;
9096
9097            filterValue->append(cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
9098        }
9099        break;
9100    }
9101    case WebKitCSSFilterValue::HueRotateFilterOperation: {
9102        // hue-rotate() takes one optional angle.
9103        if (args->size() > 1)
9104            return 0;
9105
9106        if (args->size()) {
9107            CSSParserValue* argument = args->current();
9108            if (!validUnit(argument, FAngle, CSSStrictMode))
9109                return 0;
9110
9111            filterValue->append(createPrimitiveNumericValue(argument));
9112        }
9113        break;
9114    }
9115    case WebKitCSSFilterValue::BlurFilterOperation: {
9116        // Blur takes a single length. Zero parameters are allowed.
9117        if (args->size() > 1)
9118            return 0;
9119
9120        if (args->size()) {
9121            CSSParserValue* argument = args->current();
9122            if (!validUnit(argument, FLength | FNonNeg, CSSStrictMode))
9123                return 0;
9124
9125            filterValue->append(createPrimitiveNumericValue(argument));
9126        }
9127        break;
9128    }
9129    case WebKitCSSFilterValue::DropShadowFilterOperation: {
9130        // drop-shadow() takes a single shadow.
9131        RefPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter);
9132        if (!shadowValueList || shadowValueList->length() != 1)
9133            return 0;
9134
9135        filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0));
9136        break;
9137    }
9138    default:
9139        ASSERT_NOT_REACHED();
9140    }
9141    return filterValue.release();
9142}
9143
9144PassRefPtr<CSSValueList> CSSParser::parseFilter()
9145{
9146    if (!m_valueList)
9147        return 0;
9148
9149    // The filter is a list of functional primitives that specify individual operations.
9150    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9151    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9152        if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function))
9153            return 0;
9154
9155        WebKitCSSFilterValue::FilterOperationType filterType = WebKitCSSFilterValue::UnknownFilterOperation;
9156
9157        // See if the specified primitive is one we understand.
9158        if (value->unit == CSSPrimitiveValue::CSS_URI) {
9159#if ENABLE(SVG)
9160            RefPtr<WebKitCSSFilterValue> referenceFilterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::ReferenceFilterOperation);
9161            list->append(referenceFilterValue);
9162            referenceFilterValue->append(WebKitCSSSVGDocumentValue::create(value->string));
9163#endif
9164        } else {
9165            const CSSParserString name = value->function->name;
9166            unsigned maximumArgumentCount = 1;
9167
9168            filterInfoForName(name, filterType, maximumArgumentCount);
9169
9170            if (filterType == WebKitCSSFilterValue::UnknownFilterOperation)
9171                return 0;
9172
9173#if ENABLE(CSS_SHADERS)
9174            if (filterType == WebKitCSSFilterValue::CustomFilterOperation) {
9175                // Make sure parsing fails if custom filters are disabled.
9176                if (!m_context.isCSSCustomFilterEnabled)
9177                    return 0;
9178
9179                RefPtr<WebKitCSSFilterValue> filterValue = parseCustomFilterFunction(value);
9180                if (!filterValue)
9181                    return 0;
9182                list->append(filterValue.release());
9183                continue;
9184            }
9185#endif
9186            CSSParserValueList* args = value->function->args.get();
9187            if (!args)
9188                return 0;
9189
9190            RefPtr<WebKitCSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType);
9191            if (!filterValue)
9192                return 0;
9193
9194            list->append(filterValue);
9195        }
9196    }
9197
9198    return list.release();
9199}
9200#endif
9201
9202#if ENABLE(CSS_REGIONS)
9203static bool validFlowName(const String& flowName)
9204{
9205    return !(equalIgnoringCase(flowName, "auto")
9206            || equalIgnoringCase(flowName, "default")
9207            || equalIgnoringCase(flowName, "inherit")
9208            || equalIgnoringCase(flowName, "initial")
9209            || equalIgnoringCase(flowName, "none"));
9210}
9211#endif
9212
9213bool CSSParser::cssRegionsEnabled() const
9214{
9215    return m_context.isCSSRegionsEnabled;
9216}
9217
9218bool CSSParser::cssCompositingEnabled() const
9219{
9220    return m_context.isCSSCompositingEnabled;
9221}
9222
9223bool CSSParser::cssGridLayoutEnabled() const
9224{
9225    return m_context.isCSSGridLayoutEnabled;
9226}
9227
9228#if ENABLE(CSS_REGIONS)
9229bool CSSParser::parseFlowThread(const String& flowName)
9230{
9231    setupParser("@-webkit-decls{-webkit-flow-into:", flowName, "}");
9232    cssyyparse(this);
9233
9234    m_rule = 0;
9235
9236    return ((m_parsedProperties.size() == 1) && (m_parsedProperties.first().id() == CSSPropertyWebkitFlowInto));
9237}
9238
9239// none | <ident>
9240bool CSSParser::parseFlowThread(CSSPropertyID propId, bool important)
9241{
9242    ASSERT(propId == CSSPropertyWebkitFlowInto);
9243    ASSERT(cssRegionsEnabled());
9244
9245    if (m_valueList->size() != 1)
9246        return false;
9247
9248    CSSParserValue* value = m_valueList->current();
9249    if (!value)
9250        return false;
9251
9252    if (value->unit != CSSPrimitiveValue::CSS_IDENT)
9253        return false;
9254
9255    if (value->id == CSSValueNone) {
9256        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
9257        return true;
9258    }
9259
9260    String inputProperty = String(value->string);
9261    if (!inputProperty.isEmpty()) {
9262        if (!validFlowName(inputProperty))
9263            return false;
9264        addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
9265    } else
9266        addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
9267
9268    return true;
9269}
9270
9271// -webkit-flow-from: none | <ident>
9272bool CSSParser::parseRegionThread(CSSPropertyID propId, bool important)
9273{
9274    ASSERT(propId == CSSPropertyWebkitFlowFrom);
9275    ASSERT(cssRegionsEnabled());
9276
9277    if (m_valueList->size() != 1)
9278        return false;
9279
9280    CSSParserValue* value = m_valueList->current();
9281    if (!value)
9282        return false;
9283
9284    if (value->unit != CSSPrimitiveValue::CSS_IDENT)
9285        return false;
9286
9287    if (value->id == CSSValueNone)
9288        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
9289    else {
9290        String inputProperty = String(value->string);
9291        if (!inputProperty.isEmpty()) {
9292            if (!validFlowName(inputProperty))
9293                return false;
9294            addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
9295        } else
9296            addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
9297    }
9298
9299    return true;
9300}
9301#endif
9302
9303bool CSSParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
9304{
9305    propId1 = propId;
9306    propId2 = propId;
9307    propId3 = propId;
9308    if (propId == CSSPropertyWebkitTransformOrigin) {
9309        propId1 = CSSPropertyWebkitTransformOriginX;
9310        propId2 = CSSPropertyWebkitTransformOriginY;
9311        propId3 = CSSPropertyWebkitTransformOriginZ;
9312    }
9313
9314    switch (propId) {
9315        case CSSPropertyWebkitTransformOrigin:
9316            if (!parseTransformOriginShorthand(value, value2, value3))
9317                return false;
9318            // parseTransformOriginShorthand advances the m_valueList pointer
9319            break;
9320        case CSSPropertyWebkitTransformOriginX: {
9321            value = parseFillPositionX(m_valueList.get());
9322            if (value)
9323                m_valueList->next();
9324            break;
9325        }
9326        case CSSPropertyWebkitTransformOriginY: {
9327            value = parseFillPositionY(m_valueList.get());
9328            if (value)
9329                m_valueList->next();
9330            break;
9331        }
9332        case CSSPropertyWebkitTransformOriginZ: {
9333            if (validUnit(m_valueList->current(), FLength))
9334                value = createPrimitiveNumericValue(m_valueList->current());
9335            if (value)
9336                m_valueList->next();
9337            break;
9338        }
9339        default:
9340            ASSERT_NOT_REACHED();
9341            return false;
9342    }
9343
9344    return value;
9345}
9346
9347bool CSSParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2)
9348{
9349    propId1 = propId;
9350    propId2 = propId;
9351    if (propId == CSSPropertyWebkitPerspectiveOrigin) {
9352        propId1 = CSSPropertyWebkitPerspectiveOriginX;
9353        propId2 = CSSPropertyWebkitPerspectiveOriginY;
9354    }
9355
9356    switch (propId) {
9357        case CSSPropertyWebkitPerspectiveOrigin:
9358            if (m_valueList->size() > 2)
9359                return false;
9360            parse2ValuesFillPosition(m_valueList.get(), value, value2);
9361            break;
9362        case CSSPropertyWebkitPerspectiveOriginX: {
9363            value = parseFillPositionX(m_valueList.get());
9364            if (value)
9365                m_valueList->next();
9366            break;
9367        }
9368        case CSSPropertyWebkitPerspectiveOriginY: {
9369            value = parseFillPositionY(m_valueList.get());
9370            if (value)
9371                m_valueList->next();
9372            break;
9373        }
9374        default:
9375            ASSERT_NOT_REACHED();
9376            return false;
9377    }
9378
9379    return value;
9380}
9381
9382void CSSParser::addTextDecorationProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important)
9383{
9384#if ENABLE(CSS3_TEXT)
9385    // The text-decoration-line property takes priority over text-decoration, unless the latter has important priority set.
9386    if (propId == CSSPropertyTextDecoration && !important && m_currentShorthand == CSSPropertyInvalid) {
9387        for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
9388            if (m_parsedProperties[i].id() == CSSPropertyWebkitTextDecorationLine)
9389                return;
9390        }
9391    }
9392#endif // CSS3_TEXT
9393    addProperty(propId, value, important);
9394}
9395
9396bool CSSParser::parseTextDecoration(CSSPropertyID propId, bool important)
9397{
9398    CSSParserValue* value = m_valueList->current();
9399    if (value->id == CSSValueNone) {
9400        addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
9401        m_valueList->next();
9402        return true;
9403    }
9404
9405    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9406    bool isValid = true;
9407    while (isValid && value) {
9408        switch (value->id) {
9409        case CSSValueBlink:
9410        case CSSValueLineThrough:
9411        case CSSValueOverline:
9412        case CSSValueUnderline:
9413            list->append(cssValuePool().createIdentifierValue(value->id));
9414            break;
9415        default:
9416            isValid = false;
9417            break;
9418        }
9419        if (isValid)
9420            value = m_valueList->next();
9421    }
9422
9423    if (list->length() && isValid) {
9424        addTextDecorationProperty(propId, list.release(), important);
9425        return true;
9426    }
9427
9428    return false;
9429}
9430
9431#if ENABLE(CSS3_TEXT)
9432bool CSSParser::parseTextUnderlinePosition(bool important)
9433{
9434    // The text-underline-position property has sintax "auto | alphabetic | [ under || [ left | right ] ]".
9435    // However, values 'left' and 'right' are not implemented yet, so we will parse sintax
9436    // "auto | alphabetic | under" for now.
9437    CSSParserValue* value = m_valueList->current();
9438    switch (value->id) {
9439    case CSSValueAuto:
9440    case CSSValueAlphabetic:
9441    case CSSValueUnder:
9442        if (m_valueList->next())
9443            return false;
9444
9445        addProperty(CSSPropertyWebkitTextUnderlinePosition, cssValuePool().createIdentifierValue(value->id), important);
9446        return true;
9447    }
9448    return false;
9449}
9450#endif // CSS3_TEXT
9451
9452bool CSSParser::parseTextEmphasisStyle(bool important)
9453{
9454    unsigned valueListSize = m_valueList->size();
9455
9456    RefPtr<CSSPrimitiveValue> fill;
9457    RefPtr<CSSPrimitiveValue> shape;
9458
9459    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9460        if (value->unit == CSSPrimitiveValue::CSS_STRING) {
9461            if (fill || shape || (valueListSize != 1 && !inShorthand()))
9462                return false;
9463            addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important);
9464            m_valueList->next();
9465            return true;
9466        }
9467
9468        if (value->id == CSSValueNone) {
9469            if (fill || shape || (valueListSize != 1 && !inShorthand()))
9470                return false;
9471            addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important);
9472            m_valueList->next();
9473            return true;
9474        }
9475
9476        if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
9477            if (fill)
9478                return false;
9479            fill = cssValuePool().createIdentifierValue(value->id);
9480        } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
9481            if (shape)
9482                return false;
9483            shape = cssValuePool().createIdentifierValue(value->id);
9484        } else if (!inShorthand())
9485            return false;
9486        else
9487            break;
9488    }
9489
9490    if (fill && shape) {
9491        RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
9492        parsedValues->append(fill.release());
9493        parsedValues->append(shape.release());
9494        addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
9495        return true;
9496    }
9497    if (fill) {
9498        addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
9499        return true;
9500    }
9501    if (shape) {
9502        addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
9503        return true;
9504    }
9505
9506    return false;
9507}
9508
9509PassRefPtr<CSSValue> CSSParser::parseTextIndent()
9510{
9511    // <length> | <percentage> | inherit  when CSS3_TEXT is disabled.
9512    // [ <length> | <percentage> ] && [ -webkit-hanging || -webkit-each-line ]? | inherit  when CSS3_TEXT is enabled.
9513    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
9514    bool hasLengthOrPercentage = false;
9515#if ENABLE(CSS3_TEXT)
9516    bool hasEachLine = false;
9517    bool hasHanging = false;
9518#endif
9519
9520    CSSParserValue* value = m_valueList->current();
9521    while (value) {
9522        if (!hasLengthOrPercentage && validUnit(value, FLength | FPercent)) {
9523            list->append(createPrimitiveNumericValue(value));
9524            hasLengthOrPercentage = true;
9525        }
9526#if ENABLE(CSS3_TEXT)
9527        else if (!hasEachLine && value->id == CSSValueWebkitEachLine) {
9528            list->append(cssValuePool().createIdentifierValue(CSSValueWebkitEachLine));
9529            hasEachLine = true;
9530        } else if (!hasHanging && value->id == CSSValueWebkitHanging) {
9531            list->append(cssValuePool().createIdentifierValue(CSSValueWebkitHanging));
9532            hasHanging = true;
9533        }
9534#endif
9535        else
9536            return 0;
9537
9538        value = m_valueList->next();
9539    }
9540
9541    if (!hasLengthOrPercentage)
9542        return 0;
9543
9544    return list.release();
9545}
9546
9547bool CSSParser::parseLineBoxContain(bool important)
9548{
9549    LineBoxContain lineBoxContain = LineBoxContainNone;
9550
9551    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9552        if (value->id == CSSValueBlock) {
9553            if (lineBoxContain & LineBoxContainBlock)
9554                return false;
9555            lineBoxContain |= LineBoxContainBlock;
9556        } else if (value->id == CSSValueInline) {
9557            if (lineBoxContain & LineBoxContainInline)
9558                return false;
9559            lineBoxContain |= LineBoxContainInline;
9560        } else if (value->id == CSSValueFont) {
9561            if (lineBoxContain & LineBoxContainFont)
9562                return false;
9563            lineBoxContain |= LineBoxContainFont;
9564        } else if (value->id == CSSValueGlyphs) {
9565            if (lineBoxContain & LineBoxContainGlyphs)
9566                return false;
9567            lineBoxContain |= LineBoxContainGlyphs;
9568        } else if (value->id == CSSValueReplaced) {
9569            if (lineBoxContain & LineBoxContainReplaced)
9570                return false;
9571            lineBoxContain |= LineBoxContainReplaced;
9572        } else if (value->id == CSSValueInlineBox) {
9573            if (lineBoxContain & LineBoxContainInlineBox)
9574                return false;
9575            lineBoxContain |= LineBoxContainInlineBox;
9576        } else
9577            return false;
9578    }
9579
9580    if (!lineBoxContain)
9581        return false;
9582
9583    addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
9584    return true;
9585}
9586
9587bool CSSParser::parseFontFeatureTag(CSSValueList* settings)
9588{
9589    // Feature tag name consists of 4-letter characters.
9590    static const unsigned tagNameLength = 4;
9591
9592    CSSParserValue* value = m_valueList->current();
9593    // Feature tag name comes first
9594    if (value->unit != CSSPrimitiveValue::CSS_STRING)
9595        return false;
9596    if (value->string.length() != tagNameLength)
9597        return false;
9598    for (unsigned i = 0; i < tagNameLength; ++i) {
9599        // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
9600        UChar character = value->string[i];
9601        if (character < 0x20 || character > 0x7E)
9602            return false;
9603    }
9604
9605    String tag = value->string;
9606    int tagValue = 1;
9607    // Feature tag values could follow: <integer> | on | off
9608    value = m_valueList->next();
9609    if (value) {
9610        if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
9611            tagValue = clampToInteger(value->fValue);
9612            if (tagValue < 0)
9613                return false;
9614            m_valueList->next();
9615        } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
9616            tagValue = value->id == CSSValueOn;
9617            m_valueList->next();
9618        }
9619    }
9620    settings->append(FontFeatureValue::create(tag, tagValue));
9621    return true;
9622}
9623
9624bool CSSParser::parseFontFeatureSettings(bool important)
9625{
9626    if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) {
9627        RefPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal);
9628        m_valueList->next();
9629        addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
9630        return true;
9631    }
9632
9633    RefPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
9634    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9635        if (!parseFontFeatureTag(settings.get()))
9636            return false;
9637
9638        // If the list isn't parsed fully, the current value should be comma.
9639        value = m_valueList->current();
9640        if (value && !isComma(value))
9641            return false;
9642    }
9643    if (settings->length()) {
9644        addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important);
9645        return true;
9646    }
9647    return false;
9648}
9649
9650bool CSSParser::parseFontVariantLigatures(bool important)
9651{
9652    RefPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
9653    bool sawCommonLigaturesValue = false;
9654    bool sawDiscretionaryLigaturesValue = false;
9655    bool sawHistoricalLigaturesValue = false;
9656
9657    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
9658        if (value->unit != CSSPrimitiveValue::CSS_IDENT)
9659            return false;
9660
9661        switch (value->id) {
9662        case CSSValueNoCommonLigatures:
9663        case CSSValueCommonLigatures:
9664            if (sawCommonLigaturesValue)
9665                return false;
9666            sawCommonLigaturesValue = true;
9667            ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9668            break;
9669        case CSSValueNoDiscretionaryLigatures:
9670        case CSSValueDiscretionaryLigatures:
9671            if (sawDiscretionaryLigaturesValue)
9672                return false;
9673            sawDiscretionaryLigaturesValue = true;
9674            ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9675            break;
9676        case CSSValueNoHistoricalLigatures:
9677        case CSSValueHistoricalLigatures:
9678            if (sawHistoricalLigaturesValue)
9679                return false;
9680            sawHistoricalLigaturesValue = true;
9681            ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
9682            break;
9683        default:
9684            return false;
9685        }
9686    }
9687
9688    if (!ligatureValues->length())
9689        return false;
9690
9691    addProperty(CSSPropertyWebkitFontVariantLigatures, ligatureValues.release(), important);
9692    return true;
9693}
9694
9695bool CSSParser::parseCalculation(CSSParserValue* value, CalculationPermittedValueRange range)
9696{
9697    ASSERT(isCalculation(value));
9698
9699    CSSParserValueList* args = value->function->args.get();
9700    if (!args || !args->size())
9701        return false;
9702
9703    ASSERT(!m_parsedCalculation);
9704    m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
9705
9706    if (!m_parsedCalculation)
9707        return false;
9708
9709    return true;
9710}
9711
9712#define END_TOKEN 0
9713
9714#include "CSSGrammar.h"
9715
9716enum CharacterType {
9717    // Types for the main switch.
9718
9719    // The first 4 types must be grouped together, as they
9720    // represent the allowed chars in an identifier.
9721    CharacterCaselessU,
9722    CharacterIdentifierStart,
9723    CharacterNumber,
9724    CharacterDash,
9725
9726    CharacterOther,
9727    CharacterNull,
9728    CharacterWhiteSpace,
9729    CharacterEndMediaQuery,
9730    CharacterEndNthChild,
9731    CharacterQuote,
9732    CharacterExclamationMark,
9733    CharacterHashmark,
9734    CharacterDollar,
9735    CharacterAsterisk,
9736    CharacterPlus,
9737    CharacterDot,
9738    CharacterSlash,
9739    CharacterLess,
9740    CharacterAt,
9741    CharacterBackSlash,
9742    CharacterXor,
9743    CharacterVerticalBar,
9744    CharacterTilde,
9745};
9746
9747// 128 ASCII codes
9748static const CharacterType typesOfASCIICharacters[128] = {
9749/*   0 - Null               */ CharacterNull,
9750/*   1 - Start of Heading   */ CharacterOther,
9751/*   2 - Start of Text      */ CharacterOther,
9752/*   3 - End of Text        */ CharacterOther,
9753/*   4 - End of Transm.     */ CharacterOther,
9754/*   5 - Enquiry            */ CharacterOther,
9755/*   6 - Acknowledgment     */ CharacterOther,
9756/*   7 - Bell               */ CharacterOther,
9757/*   8 - Back Space         */ CharacterOther,
9758/*   9 - Horizontal Tab     */ CharacterWhiteSpace,
9759/*  10 - Line Feed          */ CharacterWhiteSpace,
9760/*  11 - Vertical Tab       */ CharacterOther,
9761/*  12 - Form Feed          */ CharacterWhiteSpace,
9762/*  13 - Carriage Return    */ CharacterWhiteSpace,
9763/*  14 - Shift Out          */ CharacterOther,
9764/*  15 - Shift In           */ CharacterOther,
9765/*  16 - Data Line Escape   */ CharacterOther,
9766/*  17 - Device Control 1   */ CharacterOther,
9767/*  18 - Device Control 2   */ CharacterOther,
9768/*  19 - Device Control 3   */ CharacterOther,
9769/*  20 - Device Control 4   */ CharacterOther,
9770/*  21 - Negative Ack.      */ CharacterOther,
9771/*  22 - Synchronous Idle   */ CharacterOther,
9772/*  23 - End of Transmit    */ CharacterOther,
9773/*  24 - Cancel             */ CharacterOther,
9774/*  25 - End of Medium      */ CharacterOther,
9775/*  26 - Substitute         */ CharacterOther,
9776/*  27 - Escape             */ CharacterOther,
9777/*  28 - File Separator     */ CharacterOther,
9778/*  29 - Group Separator    */ CharacterOther,
9779/*  30 - Record Separator   */ CharacterOther,
9780/*  31 - Unit Separator     */ CharacterOther,
9781/*  32 - Space              */ CharacterWhiteSpace,
9782/*  33 - !                  */ CharacterExclamationMark,
9783/*  34 - "                  */ CharacterQuote,
9784/*  35 - #                  */ CharacterHashmark,
9785/*  36 - $                  */ CharacterDollar,
9786/*  37 - %                  */ CharacterOther,
9787/*  38 - &                  */ CharacterOther,
9788/*  39 - '                  */ CharacterQuote,
9789/*  40 - (                  */ CharacterOther,
9790/*  41 - )                  */ CharacterEndNthChild,
9791/*  42 - *                  */ CharacterAsterisk,
9792/*  43 - +                  */ CharacterPlus,
9793/*  44 - ,                  */ CharacterOther,
9794/*  45 - -                  */ CharacterDash,
9795/*  46 - .                  */ CharacterDot,
9796/*  47 - /                  */ CharacterSlash,
9797/*  48 - 0                  */ CharacterNumber,
9798/*  49 - 1                  */ CharacterNumber,
9799/*  50 - 2                  */ CharacterNumber,
9800/*  51 - 3                  */ CharacterNumber,
9801/*  52 - 4                  */ CharacterNumber,
9802/*  53 - 5                  */ CharacterNumber,
9803/*  54 - 6                  */ CharacterNumber,
9804/*  55 - 7                  */ CharacterNumber,
9805/*  56 - 8                  */ CharacterNumber,
9806/*  57 - 9                  */ CharacterNumber,
9807/*  58 - :                  */ CharacterOther,
9808/*  59 - ;                  */ CharacterEndMediaQuery,
9809/*  60 - <                  */ CharacterLess,
9810/*  61 - =                  */ CharacterOther,
9811/*  62 - >                  */ CharacterOther,
9812/*  63 - ?                  */ CharacterOther,
9813/*  64 - @                  */ CharacterAt,
9814/*  65 - A                  */ CharacterIdentifierStart,
9815/*  66 - B                  */ CharacterIdentifierStart,
9816/*  67 - C                  */ CharacterIdentifierStart,
9817/*  68 - D                  */ CharacterIdentifierStart,
9818/*  69 - E                  */ CharacterIdentifierStart,
9819/*  70 - F                  */ CharacterIdentifierStart,
9820/*  71 - G                  */ CharacterIdentifierStart,
9821/*  72 - H                  */ CharacterIdentifierStart,
9822/*  73 - I                  */ CharacterIdentifierStart,
9823/*  74 - J                  */ CharacterIdentifierStart,
9824/*  75 - K                  */ CharacterIdentifierStart,
9825/*  76 - L                  */ CharacterIdentifierStart,
9826/*  77 - M                  */ CharacterIdentifierStart,
9827/*  78 - N                  */ CharacterIdentifierStart,
9828/*  79 - O                  */ CharacterIdentifierStart,
9829/*  80 - P                  */ CharacterIdentifierStart,
9830/*  81 - Q                  */ CharacterIdentifierStart,
9831/*  82 - R                  */ CharacterIdentifierStart,
9832/*  83 - S                  */ CharacterIdentifierStart,
9833/*  84 - T                  */ CharacterIdentifierStart,
9834/*  85 - U                  */ CharacterCaselessU,
9835/*  86 - V                  */ CharacterIdentifierStart,
9836/*  87 - W                  */ CharacterIdentifierStart,
9837/*  88 - X                  */ CharacterIdentifierStart,
9838/*  89 - Y                  */ CharacterIdentifierStart,
9839/*  90 - Z                  */ CharacterIdentifierStart,
9840/*  91 - [                  */ CharacterOther,
9841/*  92 - \                  */ CharacterBackSlash,
9842/*  93 - ]                  */ CharacterOther,
9843/*  94 - ^                  */ CharacterXor,
9844/*  95 - _                  */ CharacterIdentifierStart,
9845/*  96 - `                  */ CharacterOther,
9846/*  97 - a                  */ CharacterIdentifierStart,
9847/*  98 - b                  */ CharacterIdentifierStart,
9848/*  99 - c                  */ CharacterIdentifierStart,
9849/* 100 - d                  */ CharacterIdentifierStart,
9850/* 101 - e                  */ CharacterIdentifierStart,
9851/* 102 - f                  */ CharacterIdentifierStart,
9852/* 103 - g                  */ CharacterIdentifierStart,
9853/* 104 - h                  */ CharacterIdentifierStart,
9854/* 105 - i                  */ CharacterIdentifierStart,
9855/* 106 - j                  */ CharacterIdentifierStart,
9856/* 107 - k                  */ CharacterIdentifierStart,
9857/* 108 - l                  */ CharacterIdentifierStart,
9858/* 109 - m                  */ CharacterIdentifierStart,
9859/* 110 - n                  */ CharacterIdentifierStart,
9860/* 111 - o                  */ CharacterIdentifierStart,
9861/* 112 - p                  */ CharacterIdentifierStart,
9862/* 113 - q                  */ CharacterIdentifierStart,
9863/* 114 - r                  */ CharacterIdentifierStart,
9864/* 115 - s                  */ CharacterIdentifierStart,
9865/* 116 - t                  */ CharacterIdentifierStart,
9866/* 117 - u                  */ CharacterCaselessU,
9867/* 118 - v                  */ CharacterIdentifierStart,
9868/* 119 - w                  */ CharacterIdentifierStart,
9869/* 120 - x                  */ CharacterIdentifierStart,
9870/* 121 - y                  */ CharacterIdentifierStart,
9871/* 122 - z                  */ CharacterIdentifierStart,
9872/* 123 - {                  */ CharacterEndMediaQuery,
9873/* 124 - |                  */ CharacterVerticalBar,
9874/* 125 - }                  */ CharacterOther,
9875/* 126 - ~                  */ CharacterTilde,
9876/* 127 - Delete             */ CharacterOther,
9877};
9878
9879// Utility functions for the CSS tokenizer.
9880
9881template <typename CharacterType>
9882static inline bool isCSSLetter(CharacterType character)
9883{
9884    return character >= 128 || typesOfASCIICharacters[character] <= CharacterDash;
9885}
9886
9887template <typename CharacterType>
9888static inline bool isCSSEscape(CharacterType character)
9889{
9890    return character >= ' ' && character != 127;
9891}
9892
9893template <typename CharacterType>
9894static inline bool isURILetter(CharacterType character)
9895{
9896    return (character >= '*' && character != 127) || (character >= '#' && character <= '&') || character == '!';
9897}
9898
9899template <typename CharacterType>
9900static inline bool isIdentifierStartAfterDash(CharacterType* currentCharacter)
9901{
9902    return isASCIIAlpha(currentCharacter[0]) || currentCharacter[0] == '_' || currentCharacter[0] >= 128
9903        || (currentCharacter[0] == '\\' && isCSSEscape(currentCharacter[1]));
9904}
9905
9906template <typename CharacterType>
9907static inline bool isEqualToCSSIdentifier(CharacterType* cssString, const char* constantString)
9908{
9909    // Compare an character memory data with a zero terminated string.
9910    do {
9911        // The input must be part of an identifier if constantChar or constString
9912        // contains '-'. Otherwise toASCIILowerUnchecked('\r') would be equal to '-'.
9913        ASSERT((*constantString >= 'a' && *constantString <= 'z') || *constantString == '-');
9914        ASSERT(*constantString != '-' || isCSSLetter(*cssString));
9915        if (toASCIILowerUnchecked(*cssString++) != (*constantString++))
9916            return false;
9917    } while (*constantString);
9918    return true;
9919}
9920
9921template <typename CharacterType>
9922static inline bool isEqualToCSSCaseSensitiveIdentifier(CharacterType* string, const char* constantString)
9923{
9924    do {
9925        if (*string++ != *constantString++)
9926            return false;
9927    } while (*constantString);
9928    return true;
9929}
9930
9931template <typename CharacterType>
9932static CharacterType* checkAndSkipEscape(CharacterType* currentCharacter)
9933{
9934    // Returns with 0, if escape check is failed. Otherwise
9935    // it returns with the following character.
9936    ASSERT(*currentCharacter == '\\');
9937
9938    ++currentCharacter;
9939    if (!isCSSEscape(*currentCharacter))
9940        return 0;
9941
9942    if (isASCIIHexDigit(*currentCharacter)) {
9943        int length = 6;
9944
9945        do {
9946            ++currentCharacter;
9947        } while (isASCIIHexDigit(*currentCharacter) && --length);
9948
9949        // Optional space after the escape sequence.
9950        if (isHTMLSpace(*currentCharacter))
9951            ++currentCharacter;
9952        return currentCharacter;
9953    }
9954    return currentCharacter + 1;
9955}
9956
9957template <typename CharacterType>
9958static inline CharacterType* skipWhiteSpace(CharacterType* currentCharacter)
9959{
9960    while (isHTMLSpace(*currentCharacter))
9961        ++currentCharacter;
9962    return currentCharacter;
9963}
9964
9965// Main CSS tokenizer functions.
9966
9967template <>
9968LChar* CSSParserString::characters<LChar>() const { return characters8(); }
9969
9970template <>
9971UChar* CSSParserString::characters<UChar>() const { return characters16(); }
9972
9973template <>
9974inline LChar*& CSSParser::currentCharacter<LChar>()
9975{
9976    return m_currentCharacter8;
9977}
9978
9979template <>
9980inline UChar*& CSSParser::currentCharacter<UChar>()
9981{
9982    return m_currentCharacter16;
9983}
9984
9985UChar*& CSSParser::currentCharacter16()
9986{
9987    if (!m_currentCharacter16) {
9988        m_dataStart16 = adoptArrayPtr(new UChar[m_length]);
9989        m_currentCharacter16 = m_dataStart16.get();
9990    }
9991
9992    return m_currentCharacter16;
9993}
9994
9995template <>
9996inline LChar* CSSParser::tokenStart<LChar>()
9997{
9998    return m_tokenStart.ptr8;
9999}
10000
10001template <>
10002inline UChar* CSSParser::tokenStart<UChar>()
10003{
10004    return m_tokenStart.ptr16;
10005}
10006
10007CSSParser::Location CSSParser::currentLocation()
10008{
10009    Location location;
10010    location.lineNumber = m_tokenStartLineNumber;
10011    if (is8BitSource())
10012        location.token.init(tokenStart<LChar>(), currentCharacter<LChar>() - tokenStart<LChar>());
10013    else
10014        location.token.init(tokenStart<UChar>(), currentCharacter<UChar>() - tokenStart<UChar>());
10015    return location;
10016}
10017
10018template <typename CharacterType>
10019inline bool CSSParser::isIdentifierStart()
10020{
10021    // Check whether an identifier is started.
10022    return isIdentifierStartAfterDash((*currentCharacter<CharacterType>() != '-') ? currentCharacter<CharacterType>() : currentCharacter<CharacterType>() + 1);
10023}
10024
10025template <typename CharacterType>
10026static inline CharacterType* checkAndSkipString(CharacterType* currentCharacter, int quote)
10027{
10028    // Returns with 0, if string check is failed. Otherwise
10029    // it returns with the following character. This is necessary
10030    // since we cannot revert escape sequences, thus strings
10031    // must be validated before parsing.
10032    while (true) {
10033        if (UNLIKELY(*currentCharacter == quote)) {
10034            // String parsing is successful.
10035            return currentCharacter + 1;
10036        }
10037        if (UNLIKELY(!*currentCharacter)) {
10038            // String parsing is successful up to end of input.
10039            return currentCharacter;
10040        }
10041        if (UNLIKELY(*currentCharacter <= '\r' && (*currentCharacter == '\n' || (*currentCharacter | 0x1) == '\r'))) {
10042            // String parsing is failed for character '\n', '\f' or '\r'.
10043            return 0;
10044        }
10045
10046        if (LIKELY(currentCharacter[0] != '\\'))
10047            ++currentCharacter;
10048        else if (currentCharacter[1] == '\n' || currentCharacter[1] == '\f')
10049            currentCharacter += 2;
10050        else if (currentCharacter[1] == '\r')
10051            currentCharacter += currentCharacter[2] == '\n' ? 3 : 2;
10052        else {
10053            currentCharacter = checkAndSkipEscape(currentCharacter);
10054            if (!currentCharacter)
10055                return 0;
10056        }
10057    }
10058}
10059
10060template <typename CharacterType>
10061unsigned CSSParser::parseEscape(CharacterType*& src)
10062{
10063    ASSERT(*src == '\\' && isCSSEscape(src[1]));
10064
10065    unsigned unicode = 0;
10066
10067    ++src;
10068    if (isASCIIHexDigit(*src)) {
10069
10070        int length = 6;
10071
10072        do {
10073            unicode = (unicode << 4) + toASCIIHexValue(*src++);
10074        } while (--length && isASCIIHexDigit(*src));
10075
10076        // Characters above 0x10ffff are not handled.
10077        if (unicode > 0x10ffff)
10078            unicode = 0xfffd;
10079
10080        // Optional space after the escape sequence.
10081        if (isHTMLSpace(*src))
10082            ++src;
10083
10084        return unicode;
10085    }
10086
10087    return *currentCharacter<CharacterType>()++;
10088}
10089
10090template <>
10091inline void CSSParser::UnicodeToChars<LChar>(LChar*& result, unsigned unicode)
10092{
10093    ASSERT(unicode <= 0xff);
10094    *result = unicode;
10095
10096    ++result;
10097}
10098
10099template <>
10100inline void CSSParser::UnicodeToChars<UChar>(UChar*& result, unsigned unicode)
10101{
10102    // Replace unicode with a surrogate pairs when it is bigger than 0xffff
10103    if (U16_LENGTH(unicode) == 2) {
10104        *result++ = U16_LEAD(unicode);
10105        *result = U16_TRAIL(unicode);
10106    } else
10107        *result = unicode;
10108
10109    ++result;
10110}
10111
10112template <typename SrcCharacterType, typename DestCharacterType>
10113inline bool CSSParser::parseIdentifierInternal(SrcCharacterType*& src, DestCharacterType*& result, bool& hasEscape)
10114{
10115    hasEscape = false;
10116    do {
10117        if (LIKELY(*src != '\\'))
10118            *result++ = *src++;
10119        else {
10120            hasEscape = true;
10121            SrcCharacterType* savedEscapeStart = src;
10122            unsigned unicode = parseEscape<SrcCharacterType>(src);
10123            if (unicode > 0xff && sizeof(DestCharacterType) == 1) {
10124                src = savedEscapeStart;
10125                return false;
10126            }
10127            UnicodeToChars(result, unicode);
10128        }
10129    } while (isCSSLetter(src[0]) || (src[0] == '\\' && isCSSEscape(src[1])));
10130
10131    return true;
10132}
10133
10134template <typename CharacterType>
10135inline void CSSParser::parseIdentifier(CharacterType*& result, CSSParserString& resultString, bool& hasEscape)
10136{
10137    // If a valid identifier start is found, we can safely
10138    // parse the identifier until the next invalid character.
10139    ASSERT(isIdentifierStart<CharacterType>());
10140
10141    CharacterType* start = currentCharacter<CharacterType>();
10142    if (UNLIKELY(!parseIdentifierInternal(currentCharacter<CharacterType>(), result, hasEscape))) {
10143        // Found an escape we couldn't handle with 8 bits, copy what has been recognized and continue
10144        ASSERT(is8BitSource());
10145        UChar*& result16 = currentCharacter16();
10146        UChar* start16 = result16;
10147        int i = 0;
10148        for (; i < result - start; i++)
10149            result16[i] = start[i];
10150
10151        result16 += i;
10152
10153        parseIdentifierInternal(currentCharacter<CharacterType>(), result16, hasEscape);
10154
10155        resultString.init(start16, result16 - start16);
10156
10157        return;
10158    }
10159
10160    resultString.init(start, result - start);
10161}
10162
10163template <typename SrcCharacterType, typename DestCharacterType>
10164inline bool CSSParser::parseStringInternal(SrcCharacterType*& src, DestCharacterType*& result, UChar quote)
10165{
10166    while (true) {
10167        if (UNLIKELY(*src == quote)) {
10168            // String parsing is done.
10169            ++src;
10170            return true;
10171        }
10172        if (UNLIKELY(!*src)) {
10173            // String parsing is done, but don't advance pointer if at the end of input.
10174            return true;
10175        }
10176        ASSERT(*src > '\r' || (*src < '\n' && *src) || *src == '\v');
10177
10178        if (LIKELY(src[0] != '\\'))
10179            *result++ = *src++;
10180        else if (src[1] == '\n' || src[1] == '\f')
10181            src += 2;
10182        else if (src[1] == '\r')
10183            src += src[2] == '\n' ? 3 : 2;
10184        else {
10185            SrcCharacterType* savedEscapeStart = src;
10186            unsigned unicode = parseEscape<SrcCharacterType>(src);
10187            if (unicode > 0xff && sizeof(DestCharacterType) == 1) {
10188                src = savedEscapeStart;
10189                return false;
10190            }
10191            UnicodeToChars(result, unicode);
10192        }
10193    }
10194
10195    return true;
10196}
10197
10198template <typename CharacterType>
10199inline void CSSParser::parseString(CharacterType*& result, CSSParserString& resultString, UChar quote)
10200{
10201    CharacterType* start = currentCharacter<CharacterType>();
10202
10203    if (UNLIKELY(!parseStringInternal(currentCharacter<CharacterType>(), result, quote))) {
10204        // Found an escape we couldn't handle with 8 bits, copy what has been recognized and continue
10205        ASSERT(is8BitSource());
10206        UChar*& result16 = currentCharacter16();
10207        UChar* start16 = result16;
10208        int i = 0;
10209        for (; i < result - start; i++)
10210            result16[i] = start[i];
10211
10212        result16 += i;
10213
10214        parseStringInternal(currentCharacter<CharacterType>(), result16, quote);
10215
10216        resultString.init(start16, result16 - start16);
10217        return;
10218    }
10219
10220    resultString.init(start, result - start);
10221}
10222
10223template <typename CharacterType>
10224inline bool CSSParser::findURI(CharacterType*& start, CharacterType*& end, UChar& quote)
10225{
10226    start = skipWhiteSpace(currentCharacter<CharacterType>());
10227
10228    if (*start == '"' || *start == '\'') {
10229        quote = *start++;
10230        end = checkAndSkipString(start, quote);
10231        if (!end)
10232            return false;
10233    } else {
10234        quote = 0;
10235        end = start;
10236        while (isURILetter(*end)) {
10237            if (LIKELY(*end != '\\'))
10238                ++end;
10239            else {
10240                end = checkAndSkipEscape(end);
10241                if (!end)
10242                    return false;
10243            }
10244        }
10245    }
10246
10247    end = skipWhiteSpace(end);
10248    if (*end != ')')
10249        return false;
10250
10251    return true;
10252}
10253
10254template <typename SrcCharacterType, typename DestCharacterType>
10255inline bool CSSParser::parseURIInternal(SrcCharacterType*& src, DestCharacterType*& dest, UChar quote)
10256{
10257    if (quote) {
10258        ASSERT(quote == '"' || quote == '\'');
10259        return parseStringInternal(src, dest, quote);
10260    }
10261
10262    while (isURILetter(*src)) {
10263        if (LIKELY(*src != '\\'))
10264            *dest++ = *src++;
10265        else {
10266            unsigned unicode = parseEscape<SrcCharacterType>(src);
10267            if (unicode > 0xff && sizeof(SrcCharacterType) == 1)
10268                return false;
10269            UnicodeToChars(dest, unicode);
10270        }
10271    }
10272
10273    return true;
10274}
10275
10276template <typename CharacterType>
10277inline void CSSParser::parseURI(CSSParserString& string)
10278{
10279    CharacterType* uriStart;
10280    CharacterType* uriEnd;
10281    UChar quote;
10282    if (!findURI(uriStart, uriEnd, quote))
10283        return;
10284
10285    CharacterType* dest = currentCharacter<CharacterType>() = uriStart;
10286    if (LIKELY(parseURIInternal(currentCharacter<CharacterType>(), dest, quote)))
10287        string.init(uriStart, dest - uriStart);
10288    else {
10289        // An escape sequence was encountered that can't be stored in 8 bits.
10290        // Reset the current character to the start of the URI and re-parse with
10291        // a 16-bit destination.
10292        ASSERT(is8BitSource());
10293        UChar* uriStart16 = currentCharacter16();
10294        currentCharacter<CharacterType>() = uriStart;
10295        bool result = parseURIInternal(currentCharacter<CharacterType>(), currentCharacter16(), quote);
10296        ASSERT_UNUSED(result, result);
10297        string.init(uriStart16, currentCharacter16() - uriStart16);
10298    }
10299
10300    currentCharacter<CharacterType>() = uriEnd + 1;
10301    m_token = URI;
10302}
10303
10304template <typename CharacterType>
10305inline bool CSSParser::parseUnicodeRange()
10306{
10307    CharacterType* character = currentCharacter<CharacterType>() + 1;
10308    int length = 6;
10309    ASSERT(*currentCharacter<CharacterType>() == '+');
10310
10311    while (isASCIIHexDigit(*character) && length) {
10312        ++character;
10313        --length;
10314    }
10315
10316    if (length && *character == '?') {
10317        // At most 5 hex digit followed by a question mark.
10318        do {
10319            ++character;
10320            --length;
10321        } while (*character == '?' && length);
10322        currentCharacter<CharacterType>() = character;
10323        return true;
10324    }
10325
10326    if (length < 6) {
10327        // At least one hex digit.
10328        if (character[0] == '-' && isASCIIHexDigit(character[1])) {
10329            // Followed by a dash and a hex digit.
10330            ++character;
10331            length = 6;
10332            do {
10333                ++character;
10334            } while (--length && isASCIIHexDigit(*character));
10335        }
10336        currentCharacter<CharacterType>() = character;
10337        return true;
10338    }
10339    return false;
10340}
10341
10342template <typename CharacterType>
10343bool CSSParser::parseNthChild()
10344{
10345    CharacterType* character = currentCharacter<CharacterType>();
10346
10347    while (isASCIIDigit(*character))
10348        ++character;
10349    if (isASCIIAlphaCaselessEqual(*character, 'n')) {
10350        currentCharacter<CharacterType>() = character + 1;
10351        return true;
10352    }
10353    return false;
10354}
10355
10356template <typename CharacterType>
10357bool CSSParser::parseNthChildExtra()
10358{
10359    CharacterType* character = skipWhiteSpace(currentCharacter<CharacterType>());
10360    if (*character != '+' && *character != '-')
10361        return false;
10362
10363    character = skipWhiteSpace(character + 1);
10364    if (!isASCIIDigit(*character))
10365        return false;
10366
10367    do {
10368        ++character;
10369    } while (isASCIIDigit(*character));
10370
10371    currentCharacter<CharacterType>() = character;
10372    return true;
10373}
10374
10375template <typename CharacterType>
10376inline bool CSSParser::detectFunctionTypeToken(int length)
10377{
10378    ASSERT(length > 0);
10379    CharacterType* name = tokenStart<CharacterType>();
10380
10381    switch (length) {
10382    case 3:
10383        if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't')) {
10384            m_token = NOTFUNCTION;
10385            return true;
10386        }
10387        if (isASCIIAlphaCaselessEqual(name[0], 'u') && isASCIIAlphaCaselessEqual(name[1], 'r') && isASCIIAlphaCaselessEqual(name[2], 'l')) {
10388            m_token = URI;
10389            return true;
10390        }
10391#if ENABLE(VIDEO_TRACK)
10392        if (isASCIIAlphaCaselessEqual(name[0], 'c') && isASCIIAlphaCaselessEqual(name[1], 'u') && isASCIIAlphaCaselessEqual(name[2], 'e')) {
10393            m_token = CUEFUNCTION;
10394            return true;
10395        }
10396#endif
10397        return false;
10398
10399    case 4:
10400        if (isEqualToCSSIdentifier(name, "calc")) {
10401            m_token = CALCFUNCTION;
10402            return true;
10403        }
10404        return false;
10405
10406    case 9:
10407        if (isEqualToCSSIdentifier(name, "nth-child")) {
10408            m_parsingMode = NthChildMode;
10409            return true;
10410        }
10411        return false;
10412
10413    case 11:
10414        if (isEqualToCSSIdentifier(name, "nth-of-type")) {
10415            m_parsingMode = NthChildMode;
10416            return true;
10417        }
10418        return false;
10419
10420    case 14:
10421        if (isEqualToCSSIdentifier(name, "nth-last-child")) {
10422            m_parsingMode = NthChildMode;
10423            return true;
10424        }
10425        return false;
10426
10427    case 16:
10428        if (isEqualToCSSIdentifier(name, "nth-last-of-type")) {
10429            m_parsingMode = NthChildMode;
10430            return true;
10431        }
10432        return false;
10433    }
10434
10435    return false;
10436}
10437
10438template <typename CharacterType>
10439inline void CSSParser::detectMediaQueryToken(int length)
10440{
10441    ASSERT(m_parsingMode == MediaQueryMode);
10442    CharacterType* name = tokenStart<CharacterType>();
10443
10444    if (length == 3) {
10445        if (isASCIIAlphaCaselessEqual(name[0], 'a') && isASCIIAlphaCaselessEqual(name[1], 'n') && isASCIIAlphaCaselessEqual(name[2], 'd'))
10446            m_token = MEDIA_AND;
10447        else if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't'))
10448            m_token = MEDIA_NOT;
10449    } else if (length == 4) {
10450        if (isASCIIAlphaCaselessEqual(name[0], 'o') && isASCIIAlphaCaselessEqual(name[1], 'n')
10451                && isASCIIAlphaCaselessEqual(name[2], 'l') && isASCIIAlphaCaselessEqual(name[3], 'y'))
10452            m_token = MEDIA_ONLY;
10453    }
10454}
10455
10456template <typename CharacterType>
10457inline void CSSParser::detectNumberToken(CharacterType* type, int length)
10458{
10459    ASSERT(length > 0);
10460
10461    switch (toASCIILowerUnchecked(type[0])) {
10462    case 'c':
10463        if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'm'))
10464            m_token = CMS;
10465        else if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'h'))
10466            m_token = CHS;
10467        return;
10468
10469    case 'd':
10470        if (length == 3 && isASCIIAlphaCaselessEqual(type[1], 'e') && isASCIIAlphaCaselessEqual(type[2], 'g'))
10471            m_token = DEGS;
10472#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
10473        else if (length > 2 && isASCIIAlphaCaselessEqual(type[1], 'p')) {
10474            if (length == 4) {
10475                // There is a discussion about the name of this unit on www-style.
10476                // Keep this compile time guard in place until that is resolved.
10477                // http://lists.w3.org/Archives/Public/www-style/2012May/0915.html
10478                if (isASCIIAlphaCaselessEqual(type[2], 'p') && isASCIIAlphaCaselessEqual(type[3], 'x'))
10479                    m_token = DPPX;
10480                else if (isASCIIAlphaCaselessEqual(type[2], 'c') && isASCIIAlphaCaselessEqual(type[3], 'm'))
10481                    m_token = DPCM;
10482            } else if (length == 3 && isASCIIAlphaCaselessEqual(type[2], 'i'))
10483                    m_token = DPI;
10484        }
10485#endif
10486        return;
10487
10488    case 'e':
10489        if (length == 2) {
10490            if (isASCIIAlphaCaselessEqual(type[1], 'm'))
10491                m_token = EMS;
10492            else if (isASCIIAlphaCaselessEqual(type[1], 'x'))
10493                m_token = EXS;
10494        }
10495        return;
10496
10497    case 'g':
10498        if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'r')
10499                && isASCIIAlphaCaselessEqual(type[2], 'a') && isASCIIAlphaCaselessEqual(type[3], 'd'))
10500            m_token = GRADS;
10501        return;
10502
10503    case 'h':
10504        if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'z'))
10505            m_token = HERTZ;
10506        return;
10507
10508    case 'i':
10509        if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'n'))
10510            m_token = INS;
10511        return;
10512
10513    case 'k':
10514        if (length == 3 && isASCIIAlphaCaselessEqual(type[1], 'h') && isASCIIAlphaCaselessEqual(type[2], 'z'))
10515            m_token = KHERTZ;
10516        return;
10517
10518    case 'm':
10519        if (length == 2) {
10520            if (isASCIIAlphaCaselessEqual(type[1], 'm'))
10521                m_token = MMS;
10522            else if (isASCIIAlphaCaselessEqual(type[1], 's'))
10523                m_token = MSECS;
10524        }
10525        return;
10526
10527    case 'p':
10528        if (length == 2) {
10529            if (isASCIIAlphaCaselessEqual(type[1], 'x'))
10530                m_token = PXS;
10531            else if (isASCIIAlphaCaselessEqual(type[1], 't'))
10532                m_token = PTS;
10533            else if (isASCIIAlphaCaselessEqual(type[1], 'c'))
10534                m_token = PCS;
10535        }
10536        return;
10537
10538    case 'r':
10539        if (length == 3) {
10540            if (isASCIIAlphaCaselessEqual(type[1], 'a') && isASCIIAlphaCaselessEqual(type[2], 'd'))
10541                m_token = RADS;
10542            else if (isASCIIAlphaCaselessEqual(type[1], 'e') && isASCIIAlphaCaselessEqual(type[2], 'm'))
10543                m_token = REMS;
10544        }
10545        return;
10546
10547    case 's':
10548        if (length == 1)
10549            m_token = SECS;
10550        return;
10551
10552    case 't':
10553        if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'u')
10554                && isASCIIAlphaCaselessEqual(type[2], 'r') && isASCIIAlphaCaselessEqual(type[3], 'n'))
10555            m_token = TURNS;
10556        return;
10557    case 'v':
10558        if (length == 2) {
10559            if (isASCIIAlphaCaselessEqual(type[1], 'w'))
10560                m_token = VW;
10561            else if (isASCIIAlphaCaselessEqual(type[1], 'h'))
10562                m_token = VH;
10563        } else if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'm')) {
10564            if (isASCIIAlphaCaselessEqual(type[2], 'i') && isASCIIAlphaCaselessEqual(type[3], 'n'))
10565                m_token = VMIN;
10566            else if (isASCIIAlphaCaselessEqual(type[2], 'a') && isASCIIAlphaCaselessEqual(type[3], 'x'))
10567                m_token = VMAX;
10568        }
10569        return;
10570
10571    default:
10572        if (type[0] == '_' && length == 5 && type[1] == '_' && isASCIIAlphaCaselessEqual(type[2], 'q')
10573                && isASCIIAlphaCaselessEqual(type[3], 'e') && isASCIIAlphaCaselessEqual(type[4], 'm'))
10574            m_token = QEMS;
10575        return;
10576    }
10577}
10578
10579template <typename CharacterType>
10580inline void CSSParser::detectDashToken(int length)
10581{
10582    CharacterType* name = tokenStart<CharacterType>();
10583
10584    if (length == 11) {
10585        if (isASCIIAlphaCaselessEqual(name[10], 'y') && isEqualToCSSIdentifier(name + 1, "webkit-an"))
10586            m_token = ANYFUNCTION;
10587        else if (isASCIIAlphaCaselessEqual(name[10], 'n') && isEqualToCSSIdentifier(name + 1, "webkit-mi"))
10588            m_token = MINFUNCTION;
10589        else if (isASCIIAlphaCaselessEqual(name[10], 'x') && isEqualToCSSIdentifier(name + 1, "webkit-ma"))
10590            m_token = MAXFUNCTION;
10591#if ENABLE(CSS_VARIABLES)
10592        else if (cssVariablesEnabled() && isASCIIAlphaCaselessEqual(name[10], 'r') && isEqualToCSSIdentifier(name + 1, "webkit-va"))
10593            m_token = VARFUNCTION;
10594#endif
10595    } else if (length == 12 && isEqualToCSSIdentifier(name + 1, "webkit-calc"))
10596        m_token = CALCFUNCTION;
10597#if ENABLE(SHADOW_DOM)
10598    else if (length == 19 && isEqualToCSSIdentifier(name + 1, "webkit-distributed"))
10599        m_token = DISTRIBUTEDFUNCTION;
10600#endif
10601}
10602
10603template <typename CharacterType>
10604inline void CSSParser::detectAtToken(int length, bool hasEscape)
10605{
10606    CharacterType* name = tokenStart<CharacterType>();
10607    ASSERT(name[0] == '@' && length >= 2);
10608
10609    // charset, font-face, import, media, namespace, page, supports,
10610    // -webkit-keyframes, and -webkit-mediaquery are not affected by hasEscape.
10611    switch (toASCIILowerUnchecked(name[1])) {
10612    case 'b':
10613        if (hasEscape)
10614            return;
10615
10616        switch (length) {
10617        case 12:
10618            if (isEqualToCSSIdentifier(name + 2, "ottom-left"))
10619                m_token = BOTTOMLEFT_SYM;
10620            return;
10621
10622        case 13:
10623            if (isEqualToCSSIdentifier(name + 2, "ottom-right"))
10624                m_token = BOTTOMRIGHT_SYM;
10625            return;
10626
10627        case 14:
10628            if (isEqualToCSSIdentifier(name + 2, "ottom-center"))
10629                m_token = BOTTOMCENTER_SYM;
10630            return;
10631
10632        case 19:
10633            if (isEqualToCSSIdentifier(name + 2, "ottom-left-corner"))
10634                m_token = BOTTOMLEFTCORNER_SYM;
10635            return;
10636
10637        case 20:
10638            if (isEqualToCSSIdentifier(name + 2, "ottom-right-corner"))
10639                m_token = BOTTOMRIGHTCORNER_SYM;
10640            return;
10641        }
10642        return;
10643
10644    case 'c':
10645        if (length == 8 && isEqualToCSSIdentifier(name + 2, "harset"))
10646            m_token = CHARSET_SYM;
10647        return;
10648
10649    case 'f':
10650        if (length == 10 && isEqualToCSSIdentifier(name + 2, "ont-face"))
10651            m_token = FONT_FACE_SYM;
10652        return;
10653
10654#if ENABLE(SHADOW_DOM)
10655    case 'h':
10656        if (length == 5 && isEqualToCSSIdentifier(name + 2, "ost"))
10657            m_token = HOST_SYM;
10658        return;
10659#endif
10660
10661    case 'i':
10662        if (length == 7 && isEqualToCSSIdentifier(name + 2, "mport")) {
10663            m_parsingMode = MediaQueryMode;
10664            m_token = IMPORT_SYM;
10665        }
10666        return;
10667
10668    case 'l':
10669        if (hasEscape)
10670            return;
10671
10672        if (length == 9) {
10673            if (isEqualToCSSIdentifier(name + 2, "eft-top"))
10674                m_token = LEFTTOP_SYM;
10675        } else if (length == 12) {
10676            // Checking the last character first could further reduce the possibile cases.
10677            if (isASCIIAlphaCaselessEqual(name[11], 'e') && isEqualToCSSIdentifier(name + 2, "eft-middl"))
10678                m_token = LEFTMIDDLE_SYM;
10679            else if (isASCIIAlphaCaselessEqual(name[11], 'm') && isEqualToCSSIdentifier(name + 2, "eft-botto"))
10680                m_token = LEFTBOTTOM_SYM;
10681        }
10682        return;
10683
10684    case 'm':
10685        if (length == 6 && isEqualToCSSIdentifier(name + 2, "edia")) {
10686            m_parsingMode = MediaQueryMode;
10687            m_token = MEDIA_SYM;
10688        }
10689        return;
10690
10691    case 'n':
10692        if (length == 10 && isEqualToCSSIdentifier(name + 2, "amespace"))
10693            m_token = NAMESPACE_SYM;
10694        return;
10695
10696    case 'p':
10697        if (length == 5 && isEqualToCSSIdentifier(name + 2, "age"))
10698            m_token = PAGE_SYM;
10699        return;
10700
10701    case 'r':
10702        if (hasEscape)
10703            return;
10704
10705        if (length == 10) {
10706            if (isEqualToCSSIdentifier(name + 2, "ight-top"))
10707                m_token = RIGHTTOP_SYM;
10708        } else if (length == 13) {
10709            // Checking the last character first could further reduce the possibile cases.
10710            if (isASCIIAlphaCaselessEqual(name[12], 'e') && isEqualToCSSIdentifier(name + 2, "ight-middl"))
10711                m_token = RIGHTMIDDLE_SYM;
10712            else if (isASCIIAlphaCaselessEqual(name[12], 'm') && isEqualToCSSIdentifier(name + 2, "ight-botto"))
10713                m_token = RIGHTBOTTOM_SYM;
10714        }
10715        return;
10716
10717#if ENABLE(CSS3_CONDITIONAL_RULES)
10718    case 's':
10719        if (length == 9 && isEqualToCSSIdentifier(name + 2, "upports")) {
10720            m_parsingMode = SupportsMode;
10721            m_token = SUPPORTS_SYM;
10722        }
10723        return;
10724#endif
10725
10726    case 't':
10727        if (hasEscape)
10728            return;
10729
10730        switch (length) {
10731        case 9:
10732            if (isEqualToCSSIdentifier(name + 2, "op-left"))
10733                m_token = TOPLEFT_SYM;
10734            return;
10735
10736        case 10:
10737            if (isEqualToCSSIdentifier(name + 2, "op-right"))
10738                m_token = TOPRIGHT_SYM;
10739            return;
10740
10741        case 11:
10742            if (isEqualToCSSIdentifier(name + 2, "op-center"))
10743                m_token = TOPCENTER_SYM;
10744            return;
10745
10746        case 16:
10747            if (isEqualToCSSIdentifier(name + 2, "op-left-corner"))
10748                m_token = TOPLEFTCORNER_SYM;
10749            return;
10750
10751        case 17:
10752            if (isEqualToCSSIdentifier(name + 2, "op-right-corner"))
10753                m_token = TOPRIGHTCORNER_SYM;
10754            return;
10755        }
10756        return;
10757
10758    case '-':
10759        switch (length) {
10760        case 13:
10761            if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-rule"))
10762                m_token = WEBKIT_RULE_SYM;
10763            return;
10764
10765        case 14:
10766            if (hasEscape)
10767                return;
10768
10769            // Checking the last character first could further reduce the possibile cases.
10770            if (isASCIIAlphaCaselessEqual(name[13], 's') && isEqualToCSSIdentifier(name + 2, "webkit-decl"))
10771                m_token = WEBKIT_DECLS_SYM;
10772            else if (isASCIIAlphaCaselessEqual(name[13], 'e') && isEqualToCSSIdentifier(name + 2, "webkit-valu"))
10773                m_token = WEBKIT_VALUE_SYM;
10774            return;
10775
10776        case 15:
10777            if (hasEscape)
10778                return;
10779
10780#if ENABLE(CSS_REGIONS)
10781            if (isASCIIAlphaCaselessEqual(name[14], 'n') && isEqualToCSSIdentifier(name + 2, "webkit-regio")) {
10782                m_token = WEBKIT_REGION_RULE_SYM;
10783                return;
10784            }
10785#endif
10786#if ENABLE(CSS_SHADERS)
10787            if (isASCIIAlphaCaselessEqual(name[14], 'r') && isEqualToCSSIdentifier(name + 2, "webkit-filte")) {
10788                m_token = WEBKIT_FILTER_RULE_SYM;
10789                return;
10790            }
10791#endif
10792            return;
10793
10794        case 17:
10795            if (hasEscape)
10796                return;
10797
10798            if (isASCIIAlphaCaselessEqual(name[16], 'r') && isEqualToCSSIdentifier(name + 2, "webkit-selecto"))
10799                m_token = WEBKIT_SELECTOR_SYM;
10800#if ENABLE(CSS_DEVICE_ADAPTATION)
10801            else if (isASCIIAlphaCaselessEqual(name[16], 't') && isEqualToCSSIdentifier(name + 2, "webkit-viewpor"))
10802                m_token = WEBKIT_VIEWPORT_RULE_SYM;
10803#endif
10804            return;
10805
10806        case 18:
10807            if (isEqualToCSSIdentifier(name + 2, "webkit-keyframes"))
10808                m_token = WEBKIT_KEYFRAMES_SYM;
10809            return;
10810
10811        case 19:
10812            if (isEqualToCSSIdentifier(name + 2, "webkit-mediaquery")) {
10813                m_parsingMode = MediaQueryMode;
10814                m_token = WEBKIT_MEDIAQUERY_SYM;
10815            }
10816            return;
10817
10818        case 22:
10819            if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-keyframe-rule"))
10820                m_token = WEBKIT_KEYFRAME_RULE_SYM;
10821            return;
10822
10823        case 27:
10824#if ENABLE(CSS3_CONDITIONAL_RULES)
10825            if (isEqualToCSSIdentifier(name + 2, "webkit-supports-condition")) {
10826                m_parsingMode = SupportsMode;
10827                m_token = WEBKIT_SUPPORTS_CONDITION_SYM;
10828            }
10829#endif
10830            return;
10831        }
10832    }
10833}
10834
10835#if ENABLE(CSS3_CONDITIONAL_RULES)
10836template <typename CharacterType>
10837inline void CSSParser::detectSupportsToken(int length)
10838{
10839    ASSERT(m_parsingMode == SupportsMode);
10840    CharacterType* name = tokenStart<CharacterType>();
10841
10842    if (length == 2) {
10843        if (isASCIIAlphaCaselessEqual(name[0], 'o') && isASCIIAlphaCaselessEqual(name[1], 'r'))
10844            m_token = SUPPORTS_OR;
10845    } else if (length == 3) {
10846        if (isASCIIAlphaCaselessEqual(name[0], 'a') && isASCIIAlphaCaselessEqual(name[1], 'n') && isASCIIAlphaCaselessEqual(name[2], 'd'))
10847            m_token = SUPPORTS_AND;
10848        else if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't'))
10849            m_token = SUPPORTS_NOT;
10850    }
10851}
10852#endif
10853
10854template <typename SrcCharacterType>
10855int CSSParser::realLex(void* yylvalWithoutType)
10856{
10857    YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType);
10858    // Write pointer for the next character.
10859    SrcCharacterType* result;
10860    CSSParserString resultString;
10861    bool hasEscape;
10862
10863    // The input buffer is terminated by a \0 character, so
10864    // it is safe to read one character ahead of a known non-null.
10865#ifndef NDEBUG
10866    // In debug we check with an ASSERT that the length is > 0 for string types.
10867    yylval->string.clear();
10868#endif
10869
10870restartAfterComment:
10871    result = currentCharacter<SrcCharacterType>();
10872    setTokenStart(result);
10873    m_tokenStartLineNumber = m_lineNumber;
10874    m_token = *currentCharacter<SrcCharacterType>();
10875    ++currentCharacter<SrcCharacterType>();
10876
10877    switch ((m_token <= 127) ? typesOfASCIICharacters[m_token] : CharacterIdentifierStart) {
10878    case CharacterCaselessU:
10879        if (UNLIKELY(*currentCharacter<SrcCharacterType>() == '+'))
10880            if (parseUnicodeRange<SrcCharacterType>()) {
10881                m_token = UNICODERANGE;
10882                yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
10883                break;
10884            }
10885        // Fall through to CharacterIdentifierStart.
10886
10887    case CharacterIdentifierStart:
10888        --currentCharacter<SrcCharacterType>();
10889        parseIdentifier(result, yylval->string, hasEscape);
10890        m_token = IDENT;
10891
10892        if (UNLIKELY(*currentCharacter<SrcCharacterType>() == '(')) {
10893#if ENABLE(CSS3_CONDITIONAL_RULES)
10894            if (m_parsingMode == SupportsMode && !hasEscape) {
10895                detectSupportsToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
10896                if (m_token != IDENT)
10897                    break;
10898            }
10899#endif
10900            m_token = FUNCTION;
10901            bool shouldSkipParenthesis = true;
10902            if (!hasEscape) {
10903                bool detected = detectFunctionTypeToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
10904                if (!detected && m_parsingMode == MediaQueryMode) {
10905                    // ... and(max-width: 480px) ... looks like a function, but in fact it is not,
10906                    // so run more detection code in the MediaQueryMode.
10907                    detectMediaQueryToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
10908                    shouldSkipParenthesis = false;
10909                }
10910            }
10911
10912            if (LIKELY(shouldSkipParenthesis)) {
10913                ++currentCharacter<SrcCharacterType>();
10914                ++result;
10915                ++yylval->string.m_length;
10916            }
10917
10918            if (token() == URI) {
10919                m_token = FUNCTION;
10920                // Check whether it is really an URI.
10921                if (yylval->string.is8Bit())
10922                    parseURI<LChar>(yylval->string);
10923                else
10924                    parseURI<UChar>(yylval->string);
10925            }
10926        } else if (UNLIKELY(m_parsingMode != NormalMode) && !hasEscape) {
10927            if (m_parsingMode == MediaQueryMode)
10928                detectMediaQueryToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
10929#if ENABLE(CSS3_CONDITIONAL_RULES)
10930            else if (m_parsingMode == SupportsMode)
10931                detectSupportsToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
10932#endif
10933            else if (m_parsingMode == NthChildMode && isASCIIAlphaCaselessEqual(tokenStart<SrcCharacterType>()[0], 'n')) {
10934                if (result - tokenStart<SrcCharacterType>() == 1) {
10935                    // String "n" is IDENT but "n+1" is NTH.
10936                    if (parseNthChildExtra<SrcCharacterType>()) {
10937                        m_token = NTH;
10938                        yylval->string.m_length = currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>();
10939                    }
10940                } else if (result - tokenStart<SrcCharacterType>() >= 2 && tokenStart<SrcCharacterType>()[1] == '-') {
10941                    // String "n-" is IDENT but "n-1" is NTH.
10942                    // Set currentCharacter to '-' to continue parsing.
10943                    SrcCharacterType* nextCharacter = result;
10944                    currentCharacter<SrcCharacterType>() = tokenStart<SrcCharacterType>() + 1;
10945                    if (parseNthChildExtra<SrcCharacterType>()) {
10946                        m_token = NTH;
10947                        yylval->string.setLength(currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
10948                    } else {
10949                        // Revert the change to currentCharacter if unsuccessful.
10950                        currentCharacter<SrcCharacterType>() = nextCharacter;
10951                    }
10952                }
10953            }
10954        }
10955        break;
10956
10957    case CharacterDot:
10958        if (!isASCIIDigit(currentCharacter<SrcCharacterType>()[0]))
10959            break;
10960        // Fall through to CharacterNumber.
10961
10962    case CharacterNumber: {
10963        bool dotSeen = (m_token == '.');
10964
10965        while (true) {
10966            if (!isASCIIDigit(currentCharacter<SrcCharacterType>()[0])) {
10967                // Only one dot is allowed for a number,
10968                // and it must be followed by a digit.
10969                if (currentCharacter<SrcCharacterType>()[0] != '.' || dotSeen || !isASCIIDigit(currentCharacter<SrcCharacterType>()[1]))
10970                    break;
10971                dotSeen = true;
10972            }
10973            ++currentCharacter<SrcCharacterType>();
10974        }
10975
10976        if (UNLIKELY(m_parsingMode == NthChildMode) && !dotSeen && isASCIIAlphaCaselessEqual(*currentCharacter<SrcCharacterType>(), 'n')) {
10977            // "[0-9]+n" is always an NthChild.
10978            ++currentCharacter<SrcCharacterType>();
10979            parseNthChildExtra<SrcCharacterType>();
10980            m_token = NTH;
10981            yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
10982            break;
10983        }
10984
10985#if ENABLE(SVG)
10986        // Use SVG parser for numbers on SVG presentation attributes.
10987        if (m_context.mode == SVGAttributeMode) {
10988            // We need to take care of units like 'em' or 'ex'.
10989            SrcCharacterType* character = currentCharacter<SrcCharacterType>();
10990            if (isASCIIAlphaCaselessEqual(*character, 'e')) {
10991                ASSERT(character - tokenStart<SrcCharacterType>() > 0);
10992                ++character;
10993                if (*character == '-' || *character == '+' || isASCIIDigit(*character)) {
10994                    ++character;
10995                    while (isASCIIDigit(*character))
10996                        ++character;
10997                    // Use FLOATTOKEN if the string contains exponents.
10998                    dotSeen = true;
10999                    currentCharacter<SrcCharacterType>() = character;
11000                }
11001            }
11002            if (!parseSVGNumber(tokenStart<SrcCharacterType>(), character - tokenStart<SrcCharacterType>(), yylval->number))
11003                break;
11004        } else
11005#endif
11006            yylval->number = charactersToDouble(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
11007
11008        // Type of the function.
11009        if (isIdentifierStart<SrcCharacterType>()) {
11010            SrcCharacterType* type = currentCharacter<SrcCharacterType>();
11011            result = currentCharacter<SrcCharacterType>();
11012
11013            parseIdentifier(result, resultString, hasEscape);
11014
11015            m_token = DIMEN;
11016            if (!hasEscape)
11017                detectNumberToken(type, currentCharacter<SrcCharacterType>() - type);
11018
11019            if (m_token == DIMEN) {
11020                // The decoded number is overwritten, but this is intentional.
11021                yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
11022            }
11023        } else if (*currentCharacter<SrcCharacterType>() == '%') {
11024            // Although the CSS grammar says {num}% we follow
11025            // webkit at the moment which uses {num}%+.
11026            do {
11027                ++currentCharacter<SrcCharacterType>();
11028            } while (*currentCharacter<SrcCharacterType>() == '%');
11029            m_token = PERCENTAGE;
11030        } else
11031            m_token = dotSeen ? FLOATTOKEN : INTEGER;
11032        break;
11033    }
11034
11035    case CharacterDash:
11036        if (isIdentifierStartAfterDash(currentCharacter<SrcCharacterType>())) {
11037            --currentCharacter<SrcCharacterType>();
11038            parseIdentifier(result, resultString, hasEscape);
11039            m_token = IDENT;
11040
11041#if ENABLE(CSS_VARIABLES)
11042            if (cssVariablesEnabled() && isEqualToCSSCaseSensitiveIdentifier(tokenStart<SrcCharacterType>() + 1, "webkit-var") && tokenStart<SrcCharacterType>()[11] == '-' && isIdentifierStartAfterDash(tokenStart<SrcCharacterType>() + 12))
11043                m_token = VAR_DEFINITION;
11044            else
11045#endif
11046            if (*currentCharacter<SrcCharacterType>() == '(') {
11047                m_token = FUNCTION;
11048                if (!hasEscape)
11049                    detectDashToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
11050                ++currentCharacter<SrcCharacterType>();
11051                ++result;
11052            } else if (UNLIKELY(m_parsingMode == NthChildMode) && !hasEscape && isASCIIAlphaCaselessEqual(tokenStart<SrcCharacterType>()[1], 'n')) {
11053                if (result - tokenStart<SrcCharacterType>() == 2) {
11054                    // String "-n" is IDENT but "-n+1" is NTH.
11055                    if (parseNthChildExtra<SrcCharacterType>()) {
11056                        m_token = NTH;
11057                        result = currentCharacter<SrcCharacterType>();
11058                    }
11059                } else if (result - tokenStart<SrcCharacterType>() >= 3 && tokenStart<SrcCharacterType>()[2] == '-') {
11060                    // String "-n-" is IDENT but "-n-1" is NTH.
11061                    // Set currentCharacter to second '-' of '-n-' to continue parsing.
11062                    SrcCharacterType* nextCharacter = result;
11063                    currentCharacter<SrcCharacterType>() = tokenStart<SrcCharacterType>() + 2;
11064                    if (parseNthChildExtra<SrcCharacterType>()) {
11065                        m_token = NTH;
11066                        result = currentCharacter<SrcCharacterType>();
11067                    } else {
11068                        // Revert the change to currentCharacter if unsuccessful.
11069                        currentCharacter<SrcCharacterType>() = nextCharacter;
11070                    }
11071                }
11072            }
11073            resultString.setLength(result - tokenStart<SrcCharacterType>());
11074            yylval->string = resultString;
11075        } else if (currentCharacter<SrcCharacterType>()[0] == '-' && currentCharacter<SrcCharacterType>()[1] == '>') {
11076            currentCharacter<SrcCharacterType>() += 2;
11077            m_token = SGML_CD;
11078        } else if (UNLIKELY(m_parsingMode == NthChildMode)) {
11079            // "-[0-9]+n" is always an NthChild.
11080            if (parseNthChild<SrcCharacterType>()) {
11081                parseNthChildExtra<SrcCharacterType>();
11082                m_token = NTH;
11083                yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
11084            }
11085        }
11086        break;
11087
11088    case CharacterOther:
11089        // m_token is simply the current character.
11090        break;
11091
11092    case CharacterNull:
11093        // Do not advance pointer at the end of input.
11094        --currentCharacter<SrcCharacterType>();
11095        break;
11096
11097    case CharacterWhiteSpace:
11098        m_token = WHITESPACE;
11099        // Might start with a '\n'.
11100        --currentCharacter<SrcCharacterType>();
11101        do {
11102            if (*currentCharacter<SrcCharacterType>() == '\n')
11103                ++m_lineNumber;
11104            ++currentCharacter<SrcCharacterType>();
11105        } while (*currentCharacter<SrcCharacterType>() <= ' ' && (typesOfASCIICharacters[*currentCharacter<SrcCharacterType>()] == CharacterWhiteSpace));
11106        break;
11107
11108    case CharacterEndMediaQuery:
11109        if (m_parsingMode == MediaQueryMode)
11110            m_parsingMode = NormalMode;
11111        break;
11112
11113    case CharacterEndNthChild:
11114        if (m_parsingMode == NthChildMode)
11115            m_parsingMode = NormalMode;
11116        break;
11117
11118    case CharacterQuote:
11119        if (checkAndSkipString(currentCharacter<SrcCharacterType>(), m_token)) {
11120            ++result;
11121            parseString<SrcCharacterType>(result, yylval->string, m_token);
11122            m_token = STRING;
11123        }
11124        break;
11125
11126    case CharacterExclamationMark: {
11127        SrcCharacterType* start = skipWhiteSpace(currentCharacter<SrcCharacterType>());
11128        if (isEqualToCSSIdentifier(start, "important")) {
11129            m_token = IMPORTANT_SYM;
11130            currentCharacter<SrcCharacterType>() = start + 9;
11131        }
11132        break;
11133    }
11134
11135    case CharacterHashmark: {
11136        SrcCharacterType* start = currentCharacter<SrcCharacterType>();
11137        result = currentCharacter<SrcCharacterType>();
11138
11139        if (isASCIIDigit(*currentCharacter<SrcCharacterType>())) {
11140            // This must be a valid hex number token.
11141            do {
11142                ++currentCharacter<SrcCharacterType>();
11143            } while (isASCIIHexDigit(*currentCharacter<SrcCharacterType>()));
11144            m_token = HEX;
11145            yylval->string.init(start, currentCharacter<SrcCharacterType>() - start);
11146        } else if (isIdentifierStart<SrcCharacterType>()) {
11147            m_token = IDSEL;
11148            parseIdentifier(result, yylval->string, hasEscape);
11149            if (!hasEscape) {
11150                // Check whether the identifier is also a valid hex number.
11151                SrcCharacterType* current = start;
11152                m_token = HEX;
11153                do {
11154                    if (!isASCIIHexDigit(*current)) {
11155                        m_token = IDSEL;
11156                        break;
11157                    }
11158                    ++current;
11159                } while (current < result);
11160            }
11161        }
11162        break;
11163    }
11164
11165    case CharacterSlash:
11166        // Ignore comments. They are not even considered as white spaces.
11167        if (*currentCharacter<SrcCharacterType>() == '*') {
11168            ++currentCharacter<SrcCharacterType>();
11169            while (currentCharacter<SrcCharacterType>()[0] != '*' || currentCharacter<SrcCharacterType>()[1] != '/') {
11170                if (*currentCharacter<SrcCharacterType>() == '\n')
11171                    ++m_lineNumber;
11172                if (*currentCharacter<SrcCharacterType>() == '\0') {
11173                    // Unterminated comments are simply ignored.
11174                    currentCharacter<SrcCharacterType>() -= 2;
11175                    break;
11176                }
11177                ++currentCharacter<SrcCharacterType>();
11178            }
11179            currentCharacter<SrcCharacterType>() += 2;
11180            goto restartAfterComment;
11181        }
11182        break;
11183
11184    case CharacterDollar:
11185        if (*currentCharacter<SrcCharacterType>() == '=') {
11186            ++currentCharacter<SrcCharacterType>();
11187            m_token = ENDSWITH;
11188        }
11189        break;
11190
11191    case CharacterAsterisk:
11192        if (*currentCharacter<SrcCharacterType>() == '=') {
11193            ++currentCharacter<SrcCharacterType>();
11194            m_token = CONTAINS;
11195        }
11196        break;
11197
11198    case CharacterPlus:
11199        if (UNLIKELY(m_parsingMode == NthChildMode)) {
11200            // Simplest case. "+[0-9]*n" is always NthChild.
11201            if (parseNthChild<SrcCharacterType>()) {
11202                parseNthChildExtra<SrcCharacterType>();
11203                m_token = NTH;
11204                yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
11205            }
11206        }
11207        break;
11208
11209    case CharacterLess:
11210        if (currentCharacter<SrcCharacterType>()[0] == '!' && currentCharacter<SrcCharacterType>()[1] == '-' && currentCharacter<SrcCharacterType>()[2] == '-') {
11211            currentCharacter<SrcCharacterType>() += 3;
11212            m_token = SGML_CD;
11213        }
11214        break;
11215
11216    case CharacterAt:
11217        if (isIdentifierStart<SrcCharacterType>()) {
11218            m_token = ATKEYWORD;
11219            ++result;
11220            parseIdentifier(result, resultString, hasEscape);
11221            detectAtToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>(), hasEscape);
11222        }
11223        break;
11224
11225    case CharacterBackSlash:
11226        if (isCSSEscape(*currentCharacter<SrcCharacterType>())) {
11227            --currentCharacter<SrcCharacterType>();
11228            parseIdentifier(result, yylval->string, hasEscape);
11229            m_token = IDENT;
11230        }
11231        break;
11232
11233    case CharacterXor:
11234        if (*currentCharacter<SrcCharacterType>() == '=') {
11235            ++currentCharacter<SrcCharacterType>();
11236            m_token = BEGINSWITH;
11237        }
11238        break;
11239
11240    case CharacterVerticalBar:
11241        if (*currentCharacter<SrcCharacterType>() == '=') {
11242            ++currentCharacter<SrcCharacterType>();
11243            m_token = DASHMATCH;
11244        }
11245        break;
11246
11247    case CharacterTilde:
11248        if (*currentCharacter<SrcCharacterType>() == '=') {
11249            ++currentCharacter<SrcCharacterType>();
11250            m_token = INCLUDES;
11251        }
11252        break;
11253
11254    default:
11255        ASSERT_NOT_REACHED();
11256        break;
11257    }
11258
11259    return token();
11260}
11261
11262CSSParserSelector* CSSParser::createFloatingSelectorWithTagName(const QualifiedName& tagQName)
11263{
11264    CSSParserSelector* selector = new CSSParserSelector(tagQName);
11265    m_floatingSelectors.add(selector);
11266    return selector;
11267}
11268
11269CSSParserSelector* CSSParser::createFloatingSelector()
11270{
11271    CSSParserSelector* selector = new CSSParserSelector;
11272    m_floatingSelectors.add(selector);
11273    return selector;
11274}
11275
11276PassOwnPtr<CSSParserSelector> CSSParser::sinkFloatingSelector(CSSParserSelector* selector)
11277{
11278    if (selector) {
11279        ASSERT(m_floatingSelectors.contains(selector));
11280        m_floatingSelectors.remove(selector);
11281    }
11282    return adoptPtr(selector);
11283}
11284
11285Vector<OwnPtr<CSSParserSelector> >* CSSParser::createFloatingSelectorVector()
11286{
11287    Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >;
11288    m_floatingSelectorVectors.add(selectorVector);
11289    return selectorVector;
11290}
11291
11292PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > CSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector)
11293{
11294    if (selectorVector) {
11295        ASSERT(m_floatingSelectorVectors.contains(selectorVector));
11296        m_floatingSelectorVectors.remove(selectorVector);
11297    }
11298    return adoptPtr(selectorVector);
11299}
11300
11301CSSParserValueList* CSSParser::createFloatingValueList()
11302{
11303    CSSParserValueList* list = new CSSParserValueList;
11304    m_floatingValueLists.add(list);
11305    return list;
11306}
11307
11308PassOwnPtr<CSSParserValueList> CSSParser::sinkFloatingValueList(CSSParserValueList* list)
11309{
11310    if (list) {
11311        ASSERT(m_floatingValueLists.contains(list));
11312        m_floatingValueLists.remove(list);
11313    }
11314    return adoptPtr(list);
11315}
11316
11317CSSParserFunction* CSSParser::createFloatingFunction()
11318{
11319    CSSParserFunction* function = new CSSParserFunction;
11320    m_floatingFunctions.add(function);
11321    return function;
11322}
11323
11324PassOwnPtr<CSSParserFunction> CSSParser::sinkFloatingFunction(CSSParserFunction* function)
11325{
11326    if (function) {
11327        ASSERT(m_floatingFunctions.contains(function));
11328        m_floatingFunctions.remove(function);
11329    }
11330    return adoptPtr(function);
11331}
11332
11333CSSParserValue& CSSParser::sinkFloatingValue(CSSParserValue& value)
11334{
11335    if (value.unit == CSSParserValue::Function) {
11336        ASSERT(m_floatingFunctions.contains(value.function));
11337        m_floatingFunctions.remove(value.function);
11338    }
11339    return value;
11340}
11341
11342MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
11343{
11344    m_floatingMediaQueryExp = MediaQueryExp::create(mediaFeature, values);
11345    return m_floatingMediaQueryExp.get();
11346}
11347
11348PassOwnPtr<MediaQueryExp> CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression)
11349{
11350    ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp);
11351    return m_floatingMediaQueryExp.release();
11352}
11353
11354Vector<OwnPtr<MediaQueryExp> >* CSSParser::createFloatingMediaQueryExpList()
11355{
11356    m_floatingMediaQueryExpList = adoptPtr(new Vector<OwnPtr<MediaQueryExp> >);
11357    return m_floatingMediaQueryExpList.get();
11358}
11359
11360PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > CSSParser::sinkFloatingMediaQueryExpList(Vector<OwnPtr<MediaQueryExp> >* list)
11361{
11362    ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList);
11363    return m_floatingMediaQueryExpList.release();
11364}
11365
11366MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const String& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
11367{
11368    m_floatingMediaQuery = adoptPtr(new MediaQuery(restrictor, mediaType, expressions));
11369    return m_floatingMediaQuery.get();
11370}
11371
11372MediaQuery* CSSParser::createFloatingMediaQuery(PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
11373{
11374    return createFloatingMediaQuery(MediaQuery::None, "all", expressions);
11375}
11376
11377PassOwnPtr<MediaQuery> CSSParser::sinkFloatingMediaQuery(MediaQuery* query)
11378{
11379    ASSERT_UNUSED(query, query == m_floatingMediaQuery);
11380    return m_floatingMediaQuery.release();
11381}
11382
11383Vector<RefPtr<StyleKeyframe> >* CSSParser::createFloatingKeyframeVector()
11384{
11385    m_floatingKeyframeVector = adoptPtr(new Vector<RefPtr<StyleKeyframe> >());
11386    return m_floatingKeyframeVector.get();
11387}
11388
11389PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > CSSParser::sinkFloatingKeyframeVector(Vector<RefPtr<StyleKeyframe> >* keyframeVector)
11390{
11391    ASSERT_UNUSED(keyframeVector, m_floatingKeyframeVector == keyframeVector);
11392    return m_floatingKeyframeVector.release();
11393}
11394
11395MediaQuerySet* CSSParser::createMediaQuerySet()
11396{
11397    RefPtr<MediaQuerySet> queries = MediaQuerySet::create();
11398    MediaQuerySet* result = queries.get();
11399    m_parsedMediaQuerySets.append(queries.release());
11400    return result;
11401}
11402
11403StyleRuleBase* CSSParser::createImportRule(const CSSParserString& url, MediaQuerySet* media)
11404{
11405    if (!media || !m_allowImportRules) {
11406        popRuleData();
11407        return 0;
11408    }
11409    RefPtr<StyleRuleImport> rule = StyleRuleImport::create(url, media);
11410    StyleRuleImport* result = rule.get();
11411    m_parsedRules.append(rule.release());
11412    processAndAddNewRuleToSourceTreeIfNeeded();
11413    return result;
11414}
11415
11416StyleRuleBase* CSSParser::createMediaRule(MediaQuerySet* media, RuleList* rules)
11417{
11418    m_allowImportRules = m_allowNamespaceDeclarations = false;
11419    RefPtr<StyleRuleMedia> rule;
11420    if (rules)
11421        rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), *rules);
11422    else {
11423        RuleList emptyRules;
11424        rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), emptyRules);
11425    }
11426    StyleRuleMedia* result = rule.get();
11427    m_parsedRules.append(rule.release());
11428    processAndAddNewRuleToSourceTreeIfNeeded();
11429    return result;
11430}
11431
11432#if ENABLE(CSS3_CONDITIONAL_RULES)
11433StyleRuleBase* CSSParser::createSupportsRule(bool conditionIsSupported, RuleList* rules)
11434{
11435    m_allowImportRules = m_allowNamespaceDeclarations = false;
11436
11437    RefPtr<CSSRuleSourceData> data = popSupportsRuleData();
11438    RefPtr<StyleRuleSupports> rule;
11439    String conditionText;
11440    unsigned conditionOffset = data->ruleHeaderRange.start + 9;
11441    unsigned conditionLength = data->ruleHeaderRange.length() - 9;
11442
11443    if (is8BitSource())
11444        conditionText = String(m_dataStart8.get() + conditionOffset, conditionLength).stripWhiteSpace();
11445    else
11446        conditionText = String(m_dataStart16.get() + conditionOffset, conditionLength).stripWhiteSpace();
11447
11448    if (rules)
11449        rule = StyleRuleSupports::create(conditionText, conditionIsSupported, *rules);
11450    else {
11451        RuleList emptyRules;
11452        rule = StyleRuleSupports::create(conditionText, conditionIsSupported, emptyRules);
11453    }
11454
11455    StyleRuleSupports* result = rule.get();
11456    m_parsedRules.append(rule.release());
11457    processAndAddNewRuleToSourceTreeIfNeeded();
11458
11459    return result;
11460}
11461
11462void CSSParser::markSupportsRuleHeaderStart()
11463{
11464    if (!m_supportsRuleDataStack)
11465        m_supportsRuleDataStack = adoptPtr(new RuleSourceDataList());
11466
11467    RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(CSSRuleSourceData::SUPPORTS_RULE);
11468    data->ruleHeaderRange.start = tokenStartOffset();
11469    m_supportsRuleDataStack->append(data);
11470}
11471
11472void CSSParser::markSupportsRuleHeaderEnd()
11473{
11474    ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
11475
11476    if (is8BitSource())
11477        m_supportsRuleDataStack->last()->ruleHeaderRange.end = tokenStart<LChar>() - m_dataStart8.get();
11478    else
11479        m_supportsRuleDataStack->last()->ruleHeaderRange.end = tokenStart<UChar>() - m_dataStart16.get();
11480}
11481
11482PassRefPtr<CSSRuleSourceData> CSSParser::popSupportsRuleData()
11483{
11484    ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
11485    RefPtr<CSSRuleSourceData> data = m_supportsRuleDataStack->last();
11486    m_supportsRuleDataStack->removeLast();
11487    return data.release();
11488}
11489
11490#endif
11491
11492CSSParser::RuleList* CSSParser::createRuleList()
11493{
11494    OwnPtr<RuleList> list = adoptPtr(new RuleList);
11495    RuleList* listPtr = list.get();
11496
11497    m_parsedRuleLists.append(list.release());
11498    return listPtr;
11499}
11500
11501void CSSParser::processAndAddNewRuleToSourceTreeIfNeeded()
11502{
11503    if (!isExtractingSourceData())
11504        return;
11505    markRuleBodyEnd();
11506    RefPtr<CSSRuleSourceData> rule = popRuleData();
11507    fixUnparsedPropertyRanges(rule.get());
11508    addNewRuleToSourceTree(rule.release());
11509}
11510
11511void CSSParser::addNewRuleToSourceTree(PassRefPtr<CSSRuleSourceData> rule)
11512{
11513    // Precondition: (isExtractingSourceData()).
11514    if (!m_ruleSourceDataResult)
11515        return;
11516    if (m_currentRuleDataStack->isEmpty())
11517        m_ruleSourceDataResult->append(rule);
11518    else
11519        m_currentRuleDataStack->last()->childRules.append(rule);
11520}
11521
11522PassRefPtr<CSSRuleSourceData> CSSParser::popRuleData()
11523{
11524    if (!m_ruleSourceDataResult)
11525        return 0;
11526
11527    ASSERT(!m_currentRuleDataStack->isEmpty());
11528    m_currentRuleData.clear();
11529    RefPtr<CSSRuleSourceData> data = m_currentRuleDataStack->last();
11530    m_currentRuleDataStack->removeLast();
11531    return data.release();
11532}
11533
11534void CSSParser::syntaxError(const Location& location, SyntaxErrorType error)
11535{
11536    if (!isLoggingErrors())
11537        return;
11538    StringBuilder builder;
11539    switch (error) {
11540    case PropertyDeclarationError:
11541        builder.appendLiteral("Invalid CSS property declaration at: ");
11542        break;
11543
11544    default:
11545        builder.appendLiteral("Unexpected CSS token: ");
11546    }
11547
11548    if (location.token.is8Bit())
11549        builder.append(location.token.characters8(), location.token.length());
11550    else
11551        builder.append(location.token.characters16(), location.token.length());
11552
11553    logError(builder.toString(), location.lineNumber);
11554
11555    m_ignoreErrorsInDeclaration = true;
11556}
11557
11558bool CSSParser::isLoggingErrors()
11559{
11560    return m_logErrors && !m_ignoreErrorsInDeclaration;
11561}
11562
11563void CSSParser::logError(const String& message, int lineNumber)
11564{
11565    // FIXME: <http://webkit.org/b/114313> CSS Parser ConsoleMessage errors should include column numbers
11566    PageConsole* console = m_styleSheet->singleOwnerDocument()->page()->console();
11567    console->addMessage(CSSMessageSource, WarningMessageLevel, message, m_styleSheet->baseURL().string(), lineNumber + 1, 0);
11568}
11569
11570StyleRuleKeyframes* CSSParser::createKeyframesRule(const String& name, PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > popKeyframes)
11571{
11572    OwnPtr<Vector<RefPtr<StyleKeyframe> > > keyframes = popKeyframes;
11573    m_allowImportRules = m_allowNamespaceDeclarations = false;
11574    RefPtr<StyleRuleKeyframes> rule = StyleRuleKeyframes::create();
11575    for (size_t i = 0; i < keyframes->size(); ++i)
11576        rule->parserAppendKeyframe(keyframes->at(i));
11577    rule->setName(name);
11578    StyleRuleKeyframes* rulePtr = rule.get();
11579    m_parsedRules.append(rule.release());
11580    processAndAddNewRuleToSourceTreeIfNeeded();
11581    return rulePtr;
11582}
11583
11584StyleRuleBase* CSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors)
11585{
11586    StyleRule* result = 0;
11587    if (selectors) {
11588        m_allowImportRules = m_allowNamespaceDeclarations = false;
11589        RefPtr<StyleRule> rule = StyleRule::create(m_lastSelectorLineNumber);
11590        rule->parserAdoptSelectorVector(*selectors);
11591        if (m_hasFontFaceOnlyValues)
11592            deleteFontFaceOnlyValues();
11593        rule->setProperties(createStylePropertySet());
11594        result = rule.get();
11595        m_parsedRules.append(rule.release());
11596        processAndAddNewRuleToSourceTreeIfNeeded();
11597    } else
11598        popRuleData();
11599    clearProperties();
11600    return result;
11601}
11602
11603StyleRuleBase* CSSParser::createFontFaceRule()
11604{
11605    m_allowImportRules = m_allowNamespaceDeclarations = false;
11606    for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
11607        CSSProperty& property = m_parsedProperties[i];
11608        if (property.id() == CSSPropertyFontVariant && property.value()->isPrimitiveValue())
11609            property.wrapValueInCommaSeparatedList();
11610        else if (property.id() == CSSPropertyFontFamily && (!property.value()->isValueList() || static_cast<CSSValueList*>(property.value())->length() != 1)) {
11611            // Unlike font-family property, font-family descriptor in @font-face rule
11612            // has to be a value list with exactly one family name. It cannot have a
11613            // have 'initial' value and cannot 'inherit' from parent.
11614            // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
11615            clearProperties();
11616            popRuleData();
11617            return 0;
11618        }
11619    }
11620    RefPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create();
11621    rule->setProperties(createStylePropertySet());
11622    clearProperties();
11623    StyleRuleFontFace* result = rule.get();
11624    m_parsedRules.append(rule.release());
11625    processAndAddNewRuleToSourceTreeIfNeeded();
11626    return result;
11627}
11628
11629#if ENABLE(SHADOW_DOM)
11630StyleRuleBase* CSSParser::createHostRule(RuleList* rules)
11631{
11632    m_allowImportRules = m_allowNamespaceDeclarations = false;
11633    RefPtr<StyleRuleHost> rule;
11634    if (rules)
11635        rule = StyleRuleHost::create(*rules);
11636    else {
11637        RuleList emptyRules;
11638        rule = StyleRuleHost::create(emptyRules);
11639    }
11640    StyleRuleHost* result = rule.get();
11641    m_parsedRules.append(rule.release());
11642    processAndAddNewRuleToSourceTreeIfNeeded();
11643    return result;
11644}
11645#endif
11646
11647void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
11648{
11649    if (!m_styleSheet || !m_allowNamespaceDeclarations)
11650        return;
11651    m_allowImportRules = false;
11652    m_styleSheet->parserAddNamespace(prefix, uri);
11653    if (prefix.isEmpty() && !uri.isNull())
11654        m_defaultNamespace = uri;
11655}
11656
11657QualifiedName CSSParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName)
11658{
11659    if (!m_styleSheet)
11660        return QualifiedName(prefix, localName, m_defaultNamespace);
11661    return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix));
11662}
11663
11664CSSParserSelector* CSSParser::rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector* specifiers)
11665{
11666    if (m_defaultNamespace != starAtom || specifiers->isCustomPseudoElement())
11667        return rewriteSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true);
11668    return specifiers;
11669}
11670
11671CSSParserSelector* CSSParser::rewriteSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
11672{
11673    AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
11674    QualifiedName tag(namespacePrefix, elementName, determinedNamespace);
11675
11676    if (!specifiers->isCustomPseudoElement()) {
11677        if (tag == anyQName())
11678            return specifiers;
11679#if ENABLE(VIDEO_TRACK)
11680        if (!(specifiers->pseudoType() == CSSSelector::PseudoCue))
11681#endif
11682            specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
11683        return specifiers;
11684    }
11685
11686    CSSParserSelector* lastShadowDescendant = specifiers;
11687    CSSParserSelector* history = specifiers;
11688    while (history->tagHistory()) {
11689        history = history->tagHistory();
11690        if (history->isCustomPseudoElement() || history->hasShadowDescendant())
11691            lastShadowDescendant = history;
11692    }
11693
11694    if (lastShadowDescendant->tagHistory()) {
11695        if (tag != anyQName())
11696            lastShadowDescendant->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
11697        return specifiers;
11698    }
11699
11700    // For shadow-ID pseudo-elements to be correctly matched, the ShadowDescendant combinator has to be used.
11701    // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
11702    OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
11703    lastShadowDescendant->setTagHistory(elementNameSelector.release());
11704    lastShadowDescendant->setRelation(CSSSelector::ShadowDescendant);
11705    return specifiers;
11706}
11707
11708CSSParserSelector* CSSParser::rewriteSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier)
11709{
11710#if ENABLE(VIDEO_TRACK)
11711    if (newSpecifier->isCustomPseudoElement() || newSpecifier->pseudoType() == CSSSelector::PseudoCue) {
11712#else
11713    if (newSpecifier->isCustomPseudoElement()) {
11714#endif
11715        // Unknown pseudo element always goes at the top of selector chain.
11716        newSpecifier->appendTagHistory(CSSSelector::ShadowDescendant, sinkFloatingSelector(specifiers));
11717        return newSpecifier;
11718    }
11719    if (specifiers->isCustomPseudoElement()) {
11720        // Specifiers for unknown pseudo element go right behind it in the chain.
11721        specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::ShadowDescendant);
11722        return specifiers;
11723    }
11724    specifiers->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier));
11725    return specifiers;
11726}
11727
11728StyleRuleBase* CSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector)
11729{
11730    // FIXME: Margin at-rules are ignored.
11731    m_allowImportRules = m_allowNamespaceDeclarations = false;
11732    StyleRulePage* pageRule = 0;
11733    if (pageSelector) {
11734        RefPtr<StyleRulePage> rule = StyleRulePage::create();
11735        Vector<OwnPtr<CSSParserSelector> > selectorVector;
11736        selectorVector.append(pageSelector);
11737        rule->parserAdoptSelectorVector(selectorVector);
11738        rule->setProperties(createStylePropertySet());
11739        pageRule = rule.get();
11740        m_parsedRules.append(rule.release());
11741        processAndAddNewRuleToSourceTreeIfNeeded();
11742    } else
11743        popRuleData();
11744    clearProperties();
11745    return pageRule;
11746}
11747
11748void CSSParser::setReusableRegionSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectors)
11749{
11750    if (selectors)
11751        m_reusableRegionSelectorVector.swap(*selectors);
11752}
11753
11754StyleRuleBase* CSSParser::createRegionRule(Vector<OwnPtr<CSSParserSelector> >* regionSelector, RuleList* rules)
11755{
11756    if (!cssRegionsEnabled() || !regionSelector || !rules) {
11757        popRuleData();
11758        return 0;
11759    }
11760
11761    m_allowImportRules = m_allowNamespaceDeclarations = false;
11762
11763    RefPtr<StyleRuleRegion> regionRule = StyleRuleRegion::create(regionSelector, *rules);
11764
11765    StyleRuleRegion* result = regionRule.get();
11766    m_parsedRules.append(regionRule.release());
11767    if (isExtractingSourceData())
11768        addNewRuleToSourceTree(CSSRuleSourceData::createUnknown());
11769
11770    return result;
11771}
11772
11773StyleRuleBase* CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
11774{
11775    // FIXME: Implement margin at-rule here, using:
11776    //        - marginBox: margin box
11777    //        - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_parsedProperties.size()] are for this at-rule.
11778    // 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.
11779
11780    endDeclarationsForMarginBox();
11781    return 0; // until this method is implemented.
11782}
11783
11784void CSSParser::startDeclarationsForMarginBox()
11785{
11786    m_numParsedPropertiesBeforeMarginBox = m_parsedProperties.size();
11787}
11788
11789void CSSParser::endDeclarationsForMarginBox()
11790{
11791    rollbackLastProperties(m_parsedProperties.size() - m_numParsedPropertiesBeforeMarginBox);
11792    m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
11793}
11794
11795void CSSParser::deleteFontFaceOnlyValues()
11796{
11797    ASSERT(m_hasFontFaceOnlyValues);
11798    for (unsigned i = 0; i < m_parsedProperties.size();) {
11799        CSSProperty& property = m_parsedProperties[i];
11800        if (property.id() == CSSPropertyFontVariant && property.value()->isValueList()) {
11801            m_parsedProperties.remove(i);
11802            continue;
11803        }
11804        ++i;
11805    }
11806}
11807
11808StyleKeyframe* CSSParser::createKeyframe(CSSParserValueList* keys)
11809{
11810    // Create a key string from the passed keys
11811    StringBuilder keyString;
11812    for (unsigned i = 0; i < keys->size(); ++i) {
11813        // Just as per the comment below, we ignore keyframes with
11814        // invalid key values (plain numbers or unknown identifiers)
11815        // marked as CSSPrimitiveValue::CSS_UNKNOWN during parsing.
11816        if (keys->valueAt(i)->unit == CSSPrimitiveValue::CSS_UNKNOWN) {
11817            clearProperties();
11818            return 0;
11819        }
11820
11821        ASSERT(keys->valueAt(i)->unit == CSSPrimitiveValue::CSS_NUMBER);
11822        float key = static_cast<float>(keys->valueAt(i)->fValue);
11823        if (key < 0 || key > 100) {
11824            // As per http://www.w3.org/TR/css3-animations/#keyframes,
11825            // "If a keyframe selector specifies negative percentage values
11826            // or values higher than 100%, then the keyframe will be ignored."
11827            clearProperties();
11828            return 0;
11829        }
11830        if (i != 0)
11831            keyString.append(',');
11832        keyString.append(String::number(key));
11833        keyString.append('%');
11834    }
11835
11836    RefPtr<StyleKeyframe> keyframe = StyleKeyframe::create();
11837    keyframe->setKeyText(keyString.toString());
11838    keyframe->setProperties(createStylePropertySet());
11839
11840    clearProperties();
11841
11842    StyleKeyframe* keyframePtr = keyframe.get();
11843    m_parsedKeyframes.append(keyframe.release());
11844    return keyframePtr;
11845}
11846
11847void CSSParser::invalidBlockHit()
11848{
11849    if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
11850        m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
11851}
11852
11853void CSSParser::updateLastSelectorLineAndPosition()
11854{
11855    m_lastSelectorLineNumber = m_lineNumber;
11856}
11857
11858void CSSParser::updateLastMediaLine(MediaQuerySet* media)
11859{
11860    media->setLastLine(m_lineNumber);
11861}
11862
11863template <typename CharacterType>
11864static inline void fixUnparsedProperties(const CharacterType* characters, CSSRuleSourceData* ruleData)
11865{
11866    Vector<CSSPropertySourceData>& propertyData = ruleData->styleSourceData->propertyData;
11867    unsigned size = propertyData.size();
11868    if (!size)
11869        return;
11870
11871    unsigned styleStart = ruleData->ruleBodyRange.start;
11872    CSSPropertySourceData* nextData = &(propertyData.at(0));
11873    for (unsigned i = 0; i < size; ++i) {
11874        CSSPropertySourceData* currentData = nextData;
11875        nextData = i < size - 1 ? &(propertyData.at(i + 1)) : 0;
11876
11877        if (currentData->parsedOk)
11878            continue;
11879        if (currentData->range.end > 0 && characters[styleStart + currentData->range.end - 1] == ';')
11880            continue;
11881
11882        unsigned propertyEndInStyleSheet;
11883        if (!nextData)
11884            propertyEndInStyleSheet = ruleData->ruleBodyRange.end - 1;
11885        else
11886            propertyEndInStyleSheet = styleStart + nextData->range.start - 1;
11887
11888        while (isHTMLSpace(characters[propertyEndInStyleSheet]))
11889            --propertyEndInStyleSheet;
11890
11891        // propertyEndInStyleSheet points at the last property text character.
11892        unsigned newPropertyEnd = propertyEndInStyleSheet - styleStart + 1; // Exclusive of the last property text character.
11893        if (currentData->range.end != newPropertyEnd) {
11894            currentData->range.end = newPropertyEnd;
11895            unsigned valueStartInStyleSheet = styleStart + currentData->range.start + currentData->name.length();
11896            while (valueStartInStyleSheet < propertyEndInStyleSheet && characters[valueStartInStyleSheet] != ':')
11897                ++valueStartInStyleSheet;
11898            if (valueStartInStyleSheet < propertyEndInStyleSheet)
11899                ++valueStartInStyleSheet; // Shift past the ':'.
11900            while (valueStartInStyleSheet < propertyEndInStyleSheet && isHTMLSpace(characters[valueStartInStyleSheet]))
11901                ++valueStartInStyleSheet;
11902            // Need to exclude the trailing ';' from the property value.
11903            currentData->value = String(characters + valueStartInStyleSheet, propertyEndInStyleSheet - valueStartInStyleSheet + (characters[propertyEndInStyleSheet] == ';' ? 0 : 1));
11904        }
11905    }
11906}
11907
11908void CSSParser::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData)
11909{
11910    if (!ruleData->styleSourceData)
11911        return;
11912
11913    if (is8BitSource()) {
11914        fixUnparsedProperties<LChar>(m_dataStart8.get() + m_parsedTextPrefixLength, ruleData);
11915        return;
11916    }
11917
11918    fixUnparsedProperties<UChar>(m_dataStart16.get() + m_parsedTextPrefixLength, ruleData);
11919}
11920
11921void CSSParser::markRuleHeaderStart(CSSRuleSourceData::Type ruleType)
11922{
11923    if (!isExtractingSourceData())
11924        return;
11925
11926    // Pop off data for a previous invalid rule.
11927    if (m_currentRuleData)
11928        m_currentRuleDataStack->removeLast();
11929
11930    RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(ruleType);
11931    data->ruleHeaderRange.start = tokenStartOffset();
11932    m_currentRuleData = data;
11933    m_currentRuleDataStack->append(data.release());
11934}
11935
11936template <typename CharacterType>
11937inline void CSSParser::setRuleHeaderEnd(const CharacterType* dataStart)
11938{
11939    CharacterType* listEnd = tokenStart<CharacterType>();
11940    while (listEnd > dataStart + 1) {
11941        if (isHTMLSpace(*(listEnd - 1)))
11942            --listEnd;
11943        else
11944            break;
11945    }
11946
11947    m_currentRuleDataStack->last()->ruleHeaderRange.end = listEnd - dataStart;
11948}
11949
11950void CSSParser::markRuleHeaderEnd()
11951{
11952    if (!isExtractingSourceData())
11953        return;
11954    ASSERT(!m_currentRuleDataStack->isEmpty());
11955
11956    if (is8BitSource())
11957        setRuleHeaderEnd<LChar>(m_dataStart8.get());
11958    else
11959        setRuleHeaderEnd<UChar>(m_dataStart16.get());
11960}
11961
11962void CSSParser::markSelectorStart()
11963{
11964    if (!isExtractingSourceData())
11965        return;
11966    ASSERT(!m_selectorRange.end);
11967
11968    m_selectorRange.start = tokenStartOffset();
11969}
11970
11971void CSSParser::markSelectorEnd()
11972{
11973    if (!isExtractingSourceData())
11974        return;
11975    ASSERT(!m_selectorRange.end);
11976    ASSERT(m_currentRuleDataStack->size());
11977
11978    m_selectorRange.end = tokenStartOffset();
11979    m_currentRuleDataStack->last()->selectorRanges.append(m_selectorRange);
11980    m_selectorRange.start = 0;
11981    m_selectorRange.end = 0;
11982}
11983
11984void CSSParser::markRuleBodyStart()
11985{
11986    if (!isExtractingSourceData())
11987        return;
11988    m_currentRuleData.clear();
11989    unsigned offset = tokenStartOffset();
11990    if (tokenStartChar() == '{')
11991        ++offset; // Skip the rule body opening brace.
11992    ASSERT(!m_currentRuleDataStack->isEmpty());
11993    m_currentRuleDataStack->last()->ruleBodyRange.start = offset;
11994}
11995
11996void CSSParser::markRuleBodyEnd()
11997{
11998    // Precondition: (!isExtractingSourceData())
11999    unsigned offset = tokenStartOffset();
12000    ASSERT(!m_currentRuleDataStack->isEmpty());
12001    m_currentRuleDataStack->last()->ruleBodyRange.end = offset;
12002}
12003
12004void CSSParser::markPropertyStart()
12005{
12006    m_ignoreErrorsInDeclaration = false;
12007    if (!isExtractingSourceData())
12008        return;
12009    if (m_currentRuleDataStack->isEmpty() || !m_currentRuleDataStack->last()->styleSourceData)
12010        return;
12011
12012    m_propertyRange.start = tokenStartOffset();
12013}
12014
12015void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed)
12016{
12017    if (!isExtractingSourceData())
12018        return;
12019    if (m_currentRuleDataStack->isEmpty() || !m_currentRuleDataStack->last()->styleSourceData)
12020        return;
12021
12022    unsigned offset = tokenStartOffset();
12023    if (tokenStartChar() == ';') // Include semicolon into the property text.
12024        ++offset;
12025    m_propertyRange.end = offset;
12026    if (m_propertyRange.start != UINT_MAX && !m_currentRuleDataStack->isEmpty()) {
12027        // This stuff is only executed when the style data retrieval is requested by client.
12028        const unsigned start = m_propertyRange.start;
12029        const unsigned end = m_propertyRange.end;
12030        ASSERT(start < end);
12031        String propertyString;
12032        if (is8BitSource())
12033            propertyString = String(m_dataStart8.get() + start, end - start).stripWhiteSpace();
12034        else
12035            propertyString = String(m_dataStart16.get() + start, end - start).stripWhiteSpace();
12036        if (propertyString.endsWith(';'))
12037            propertyString = propertyString.left(propertyString.length() - 1);
12038        size_t colonIndex = propertyString.find(':');
12039        ASSERT(colonIndex != notFound);
12040
12041        String name = propertyString.left(colonIndex).stripWhiteSpace();
12042        String value = propertyString.substring(colonIndex + 1, propertyString.length()).stripWhiteSpace();
12043        // The property range is relative to the declaration start offset.
12044        SourceRange& topRuleBodyRange = m_currentRuleDataStack->last()->ruleBodyRange;
12045        m_currentRuleDataStack->last()->styleSourceData->propertyData.append(
12046            CSSPropertySourceData(name, value, isImportantFound, isPropertyParsed, SourceRange(start - topRuleBodyRange.start, end - topRuleBodyRange.start)));
12047    }
12048    resetPropertyRange();
12049}
12050
12051#if ENABLE(CSS_DEVICE_ADAPTATION)
12052StyleRuleBase* CSSParser::createViewportRule()
12053{
12054    m_allowImportRules = m_allowNamespaceDeclarations = false;
12055
12056    RefPtr<StyleRuleViewport> rule = StyleRuleViewport::create();
12057
12058    rule->setProperties(createStylePropertySet());
12059    clearProperties();
12060
12061    StyleRuleViewport* result = rule.get();
12062    m_parsedRules.append(rule.release());
12063    processAndAddNewRuleToSourceTreeIfNeeded();
12064
12065    return result;
12066}
12067
12068bool CSSParser::parseViewportProperty(CSSPropertyID propId, bool important)
12069{
12070    CSSParserValue* value = m_valueList->current();
12071    if (!value)
12072        return false;
12073
12074    int id = value->id;
12075    bool validPrimitive = false;
12076
12077    switch (propId) {
12078    case CSSPropertyMinWidth: // auto | device-width | device-height | <length> | <percentage>
12079    case CSSPropertyMaxWidth:
12080    case CSSPropertyMinHeight:
12081    case CSSPropertyMaxHeight:
12082        if (id == CSSValueAuto || id == CSSValueDeviceWidth || id == CSSValueDeviceHeight)
12083            validPrimitive = true;
12084        else
12085            validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
12086        break;
12087    case CSSPropertyWidth: // shorthand
12088        return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMaxWidth, important);
12089    case CSSPropertyHeight:
12090        return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyMaxHeight, important);
12091    case CSSPropertyMinZoom: // auto | <number> | <percentage>
12092    case CSSPropertyMaxZoom:
12093    case CSSPropertyZoom:
12094        if (id == CSSValueAuto)
12095            validPrimitive = true;
12096        else
12097            validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg));
12098        break;
12099    case CSSPropertyUserZoom: // zoom | fixed
12100        if (id == CSSValueZoom || id == CSSValueFixed)
12101            validPrimitive = true;
12102        break;
12103    case CSSPropertyOrientation: // auto | portrait | landscape
12104        if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandscape)
12105            validPrimitive = true;
12106    default:
12107        break;
12108    }
12109
12110    RefPtr<CSSValue> parsedValue;
12111    if (validPrimitive) {
12112        parsedValue = parseValidPrimitive(id, value);
12113        m_valueList->next();
12114    }
12115
12116    if (parsedValue) {
12117        if (!m_valueList->current() || inShorthand()) {
12118            addProperty(propId, parsedValue.release(), important);
12119            return true;
12120        }
12121    }
12122
12123    return false;
12124}
12125
12126bool CSSParser::parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first, CSSPropertyID second, bool important)
12127{
12128    unsigned numValues = m_valueList->size();
12129
12130    if (numValues > 2)
12131        return false;
12132
12133    ShorthandScope scope(this, propId);
12134
12135    if (!parseViewportProperty(first, important))
12136        return false;
12137
12138    // If just one value is supplied, the second value
12139    // is implicitly initialized with the first value.
12140    if (numValues == 1)
12141        m_valueList->previous();
12142
12143    return parseViewportProperty(second, important);
12144}
12145#endif
12146
12147template <typename CharacterType>
12148static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
12149{
12150    char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
12151
12152    for (unsigned i = 0; i != length; ++i) {
12153        CharacterType c = propertyName[i];
12154        if (c == 0 || c >= 0x7F)
12155            return CSSPropertyInvalid; // illegal character
12156        buffer[i] = toASCIILower(c);
12157    }
12158    buffer[length] = '\0';
12159
12160    const char* name = buffer;
12161    if (buffer[0] == '-') {
12162#if ENABLE(LEGACY_CSS_VENDOR_PREFIXES)
12163        // If the prefix is -apple- or -khtml-, change it to -webkit-.
12164        // This makes the string one character longer.
12165        if (RuntimeEnabledFeatures::legacyCSSVendorPrefixesEnabled()
12166            && (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-"))) {
12167            memmove(buffer + 7, buffer + 6, length + 1 - 6);
12168            memcpy(buffer, "-webkit", 7);
12169            ++length;
12170        }
12171#endif
12172#if PLATFORM(IOS)
12173        cssPropertyNameIOSAliasing(buffer, name, length);
12174#endif
12175    }
12176
12177    const Property* hashTableEntry = findProperty(name, length);
12178    const CSSPropertyID propertyID = hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
12179
12180    static const int cssPropertyHistogramSize = numCSSProperties;
12181    if (hasPrefix(buffer, length, "-webkit-") && propertyID != CSSPropertyInvalid) {
12182        int histogramValue = propertyID - firstCSSProperty;
12183        ASSERT(0 <= histogramValue && histogramValue < cssPropertyHistogramSize);
12184        HistogramSupport::histogramEnumeration("CSS.PrefixUsage", histogramValue, cssPropertyHistogramSize);
12185    }
12186
12187    return propertyID;
12188}
12189
12190CSSPropertyID cssPropertyID(const String& string)
12191{
12192    unsigned length = string.length();
12193
12194    if (!length)
12195        return CSSPropertyInvalid;
12196    if (length > maxCSSPropertyNameLength)
12197        return CSSPropertyInvalid;
12198
12199    return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters(), length);
12200}
12201
12202CSSPropertyID cssPropertyID(const CSSParserString& string)
12203{
12204    unsigned length = string.length();
12205
12206    if (!length)
12207        return CSSPropertyInvalid;
12208    if (length > maxCSSPropertyNameLength)
12209        return CSSPropertyInvalid;
12210
12211    return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
12212}
12213
12214#if PLATFORM(IOS)
12215void cssPropertyNameIOSAliasing(const char* propertyName, const char*& propertyNameAlias, unsigned& newLength)
12216{
12217    if (!strcmp(propertyName, "-webkit-hyphenate-locale")) {
12218        // Worked in iOS 4.2.
12219        static const char* const webkitLocale = "-webkit-locale";
12220        propertyNameAlias = webkitLocale;
12221        newLength = strlen(webkitLocale);
12222    }
12223}
12224#endif
12225
12226template <typename CharacterType>
12227static int cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
12228{
12229    char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
12230
12231    for (unsigned i = 0; i != length; ++i) {
12232        CharacterType c = valueKeyword[i];
12233        if (c == 0 || c >= 0x7F)
12234            return 0; // illegal character
12235        buffer[i] = WTF::toASCIILower(c);
12236    }
12237    buffer[length] = '\0';
12238
12239    if (buffer[0] == '-') {
12240        // If the prefix is -apple- or -khtml-, change it to -webkit-.
12241        // This makes the string one character longer.
12242        if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
12243            memmove(buffer + 7, buffer + 6, length + 1 - 6);
12244            memcpy(buffer, "-webkit", 7);
12245            ++length;
12246        }
12247    }
12248
12249    const Value* hashTableEntry = findValue(buffer, length);
12250    return hashTableEntry ? hashTableEntry->id : 0;
12251}
12252
12253int cssValueKeywordID(const CSSParserString& string)
12254{
12255    unsigned length = string.length();
12256    if (!length)
12257        return 0;
12258    if (length > maxCSSValueKeywordLength)
12259        return 0;
12260
12261    return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
12262}
12263
12264template <typename CharacterType>
12265static inline bool isCSSTokenizerIdentifier(const CharacterType* characters, unsigned length)
12266{
12267    const CharacterType* end = characters + length;
12268
12269    // -?
12270    if (characters != end && characters[0] == '-')
12271        ++characters;
12272
12273    // {nmstart}
12274    if (characters == end || !(characters[0] == '_' || characters[0] >= 128 || isASCIIAlpha(characters[0])))
12275        return false;
12276    ++characters;
12277
12278    // {nmchar}*
12279    for (; characters != end; ++characters) {
12280        if (!(characters[0] == '_' || characters[0] == '-' || characters[0] >= 128 || isASCIIAlphanumeric(characters[0])))
12281            return false;
12282    }
12283
12284    return true;
12285}
12286
12287// "ident" from the CSS tokenizer, minus backslash-escape sequences
12288static bool isCSSTokenizerIdentifier(const String& string)
12289{
12290    unsigned length = string.length();
12291
12292    if (!length)
12293        return false;
12294
12295    if (string.is8Bit())
12296        return isCSSTokenizerIdentifier(string.characters8(), length);
12297    return isCSSTokenizerIdentifier(string.characters(), length);
12298}
12299
12300template <typename CharacterType>
12301static inline bool isCSSTokenizerURL(const CharacterType* characters, unsigned length)
12302{
12303    const CharacterType* end = characters + length;
12304
12305    for (; characters != end; ++characters) {
12306        CharacterType c = characters[0];
12307        switch (c) {
12308            case '!':
12309            case '#':
12310            case '$':
12311            case '%':
12312            case '&':
12313                break;
12314            default:
12315                if (c < '*')
12316                    return false;
12317                if (c <= '~')
12318                    break;
12319                if (c < 128)
12320                    return false;
12321        }
12322    }
12323
12324    return true;
12325}
12326
12327// "url" from the CSS tokenizer, minus backslash-escape sequences
12328static bool isCSSTokenizerURL(const String& string)
12329{
12330    unsigned length = string.length();
12331
12332    if (!length)
12333        return true;
12334
12335    if (string.is8Bit())
12336        return isCSSTokenizerURL(string.characters8(), length);
12337    return isCSSTokenizerURL(string.characters(), length);
12338}
12339
12340
12341template <typename CharacterType>
12342static inline String quoteCSSStringInternal(const CharacterType* characters, unsigned length)
12343{
12344    // For efficiency, we first pre-calculate the length of the quoted string, then we build the actual one.
12345    // Please see below for the actual logic.
12346    unsigned quotedStringSize = 2; // Two quotes surrounding the entire string.
12347    bool afterEscape = false;
12348    for (unsigned i = 0; i < length; ++i) {
12349        CharacterType ch = characters[i];
12350        if (ch == '\\' || ch == '\'') {
12351            quotedStringSize += 2;
12352            afterEscape = false;
12353        } else if (ch < 0x20 || ch == 0x7F) {
12354            quotedStringSize += 2 + (ch >= 0x10);
12355            afterEscape = true;
12356        } else {
12357            quotedStringSize += 1 + (afterEscape && (isASCIIHexDigit(ch) || ch == ' '));
12358            afterEscape = false;
12359        }
12360    }
12361
12362    StringBuffer<CharacterType> buffer(quotedStringSize);
12363    unsigned index = 0;
12364    buffer[index++] = '\'';
12365    afterEscape = false;
12366    for (unsigned i = 0; i < length; ++i) {
12367        CharacterType ch = characters[i];
12368        if (ch == '\\' || ch == '\'') {
12369            buffer[index++] = '\\';
12370            buffer[index++] = ch;
12371            afterEscape = false;
12372        } else if (ch < 0x20 || ch == 0x7F) { // Control characters.
12373            buffer[index++] = '\\';
12374            placeByteAsHexCompressIfPossible(ch, buffer, index, Lowercase);
12375            afterEscape = true;
12376        } else {
12377            // Space character may be required to separate backslash-escape sequence and normal characters.
12378            if (afterEscape && (isASCIIHexDigit(ch) || ch == ' '))
12379                buffer[index++] = ' ';
12380            buffer[index++] = ch;
12381            afterEscape = false;
12382        }
12383    }
12384    buffer[index++] = '\'';
12385
12386    ASSERT(quotedStringSize == index);
12387    return String::adopt(buffer);
12388}
12389
12390// We use single quotes for now because markup.cpp uses double quotes.
12391String quoteCSSString(const String& string)
12392{
12393    // This function expands each character to at most 3 characters ('\u0010' -> '\' '1' '0') as well as adds
12394    // 2 quote characters (before and after). Make sure the resulting size (3 * length + 2) will not overflow unsigned.
12395
12396    unsigned length = string.length();
12397
12398    if (!length)
12399        return String("\'\'");
12400
12401    if (length > std::numeric_limits<unsigned>::max() / 3 - 2)
12402        return emptyString();
12403
12404    if (string.is8Bit())
12405        return quoteCSSStringInternal(string.characters8(), length);
12406    return quoteCSSStringInternal(string.characters16(), length);
12407}
12408
12409String quoteCSSStringIfNeeded(const String& string)
12410{
12411    return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string);
12412}
12413
12414String quoteCSSURLIfNeeded(const String& string)
12415{
12416    return isCSSTokenizerURL(string) ? string : quoteCSSString(string);
12417}
12418
12419bool isValidNthToken(const CSSParserString& token)
12420{
12421    // The tokenizer checks for the construct of an+b.
12422    // However, since the {ident} rule precedes the {nth} rule, some of those
12423    // tokens are identified as string literal. Furthermore we need to accept
12424    // "odd" and "even" which does not match to an+b.
12425    return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
12426        || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");
12427}
12428
12429}
12430