CSSParser.cpp revision 54cdeeebc7adcbcd900e8b6a141a8cae27d9a631
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 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 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB.  If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25#include "config.h"
26#include "CSSParser.h"
27
28#include "CSSBorderImageValue.h"
29#include "CSSCanvasValue.h"
30#include "CSSCharsetRule.h"
31#include "CSSCursorImageValue.h"
32#include "CSSFontFaceRule.h"
33#include "CSSFontFaceSrcValue.h"
34#include "CSSGradientValue.h"
35#include "CSSImageValue.h"
36#include "CSSImportRule.h"
37#include "CSSInheritedValue.h"
38#include "CSSInitialValue.h"
39#include "CSSLineBoxContainValue.h"
40#include "CSSMediaRule.h"
41#include "CSSMutableStyleDeclaration.h"
42#include "CSSPageRule.h"
43#include "CSSPrimitiveValue.h"
44#include "CSSPrimitiveValueCache.h"
45#include "CSSProperty.h"
46#include "CSSPropertyNames.h"
47#include "CSSPropertySourceData.h"
48#include "CSSQuirkPrimitiveValue.h"
49#include "CSSReflectValue.h"
50#include "CSSRuleList.h"
51#include "CSSSelector.h"
52#include "CSSStyleRule.h"
53#include "CSSStyleSheet.h"
54#include "CSSTimingFunctionValue.h"
55#include "CSSUnicodeRangeValue.h"
56#include "CSSValueKeywords.h"
57#include "CSSValueList.h"
58#include "Counter.h"
59#include "Document.h"
60#include "FloatConversion.h"
61#include "FontFamilyValue.h"
62#include "FontValue.h"
63#include "HTMLParserIdioms.h"
64#include "HashTools.h"
65#include "MediaList.h"
66#include "MediaQueryExp.h"
67#include "Page.h"
68#include "Pair.h"
69#include "Rect.h"
70#include "RenderTheme.h"
71#include "ShadowValue.h"
72#include "WebKitCSSKeyframeRule.h"
73#include "WebKitCSSKeyframesRule.h"
74#include "WebKitCSSTransformValue.h"
75#include <limits.h>
76#include <wtf/HexNumber.h>
77#include <wtf/dtoa.h>
78#include <wtf/text/StringBuffer.h>
79
80#if ENABLE(DASHBOARD_SUPPORT)
81#include "DashboardRegion.h"
82#endif
83
84#define YYDEBUG 0
85
86#if YYDEBUG > 0
87extern int cssyydebug;
88#endif
89
90extern int cssyyparse(void* parser);
91
92using namespace std;
93using namespace WTF;
94
95#ifdef ANDROID_INSTRUMENT
96#include "TimeCounter.h"
97#endif
98
99namespace WebCore {
100
101static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
102static const double MAX_SCALE = 1000000;
103
104static bool equal(const CSSParserString& a, const char* b)
105{
106    for (int i = 0; i < a.length; ++i) {
107        if (!b[i])
108            return false;
109        if (a.characters[i] != b[i])
110            return false;
111    }
112    return !b[a.length];
113}
114
115static bool equalIgnoringCase(const CSSParserString& a, const char* b)
116{
117    for (int i = 0; i < a.length; ++i) {
118        if (!b[i])
119            return false;
120        ASSERT(!isASCIIUpper(b[i]));
121        if (toASCIILower(a.characters[i]) != b[i])
122            return false;
123    }
124    return !b[a.length];
125}
126
127static bool hasPrefix(const char* string, unsigned length, const char* prefix)
128{
129    for (unsigned i = 0; i < length; ++i) {
130        if (!prefix[i])
131            return true;
132        if (string[i] != prefix[i])
133            return false;
134    }
135    return false;
136}
137
138CSSParser::CSSParser(bool strictParsing)
139    : m_strict(strictParsing)
140    , m_important(false)
141    , m_id(0)
142    , m_styleSheet(0)
143    , m_valueList(0)
144    , m_parsedProperties(static_cast<CSSProperty**>(fastMalloc(32 * sizeof(CSSProperty*))))
145    , m_numParsedProperties(0)
146    , m_maxParsedProperties(32)
147    , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
148    , m_inParseShorthand(0)
149    , m_currentShorthand(0)
150    , m_implicitShorthand(false)
151    , m_hasFontFaceOnlyValues(false)
152    , m_hadSyntacticallyValidCSSRule(false)
153    , m_defaultNamespace(starAtom)
154    , m_inStyleRuleOrDeclaration(false)
155    , m_selectorListRange(0, 0)
156    , m_ruleBodyRange(0, 0)
157    , m_propertyRange(UINT_MAX, UINT_MAX)
158    , m_ruleRangeMap(0)
159    , m_currentRuleData(0)
160    , m_data(0)
161    , yy_start(1)
162    , m_lineNumber(0)
163    , m_lastSelectorLineNumber(0)
164    , m_allowImportRules(true)
165    , m_allowNamespaceDeclarations(true)
166{
167#if YYDEBUG > 0
168    cssyydebug = 1;
169#endif
170    CSSPropertySourceData::init();
171}
172
173CSSParser::~CSSParser()
174{
175    clearProperties();
176    fastFree(m_parsedProperties);
177
178    delete m_valueList;
179
180    fastFree(m_data);
181
182    fastDeleteAllValues(m_floatingSelectors);
183    deleteAllValues(m_floatingSelectorVectors);
184    deleteAllValues(m_floatingValueLists);
185    deleteAllValues(m_floatingFunctions);
186}
187
188void CSSParserString::lower()
189{
190    // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
191    // that can potentially change the length of the string rather than the character
192    // by character kind. If we don't need Unicode lowercasing, it would be good to
193    // simplify this function.
194
195    if (charactersAreAllASCII(characters, length)) {
196        // Fast case for all-ASCII.
197        for (int i = 0; i < length; i++)
198            characters[i] = toASCIILower(characters[i]);
199    } else {
200        for (int i = 0; i < length; i++)
201            characters[i] = Unicode::toLower(characters[i]);
202    }
203}
204
205void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix)
206{
207    int length = string.length() + strlen(prefix) + strlen(suffix) + 2;
208
209    fastFree(m_data);
210    m_data = static_cast<UChar*>(fastMalloc(length * sizeof(UChar)));
211    for (unsigned i = 0; i < strlen(prefix); i++)
212        m_data[i] = prefix[i];
213
214    memcpy(m_data + strlen(prefix), string.characters(), string.length() * sizeof(UChar));
215
216    unsigned start = strlen(prefix) + string.length();
217    unsigned end = start + strlen(suffix);
218    for (unsigned i = start; i < end; i++)
219        m_data[i] = suffix[i - start];
220
221    m_data[length - 1] = 0;
222    m_data[length - 2] = 0;
223
224    yy_hold_char = 0;
225    yyleng = 0;
226    yytext = yy_c_buf_p = m_data;
227    yy_hold_char = *yy_c_buf_p;
228    resetRuleBodyMarks();
229}
230
231void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string, int startLineNumber, StyleRuleRangeMap* ruleRangeMap)
232{
233#ifdef ANDROID_INSTRUMENT
234    android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
235#endif
236    setStyleSheet(sheet);
237    m_defaultNamespace = starAtom; // Reset the default namespace.
238    m_ruleRangeMap = ruleRangeMap;
239    if (ruleRangeMap) {
240        m_currentRuleData = CSSRuleSourceData::create();
241        m_currentRuleData->styleSourceData = CSSStyleSourceData::create();
242    }
243
244    m_lineNumber = startLineNumber;
245    setupParser("", string, "");
246    cssyyparse(this);
247    m_ruleRangeMap = 0;
248    m_currentRuleData = 0;
249    m_rule = 0;
250#ifdef ANDROID_INSTRUMENT
251    android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
252#endif
253}
254
255PassRefPtr<CSSRule> CSSParser::parseRule(CSSStyleSheet* sheet, const String& string)
256{
257#ifdef ANDROID_INSTRUMENT
258    android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
259#endif
260    setStyleSheet(sheet);
261    m_allowNamespaceDeclarations = false;
262    setupParser("@-webkit-rule{", string, "} ");
263    cssyyparse(this);
264#ifdef ANDROID_INSTRUMENT
265    android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
266#endif
267    return m_rule.release();
268}
269
270PassRefPtr<CSSRule> CSSParser::parseKeyframeRule(CSSStyleSheet *sheet, const String &string)
271{
272#ifdef ANDROID_INSTRUMENT
273    android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
274#endif
275    setStyleSheet(sheet);
276    setupParser("@-webkit-keyframe-rule{ ", string, "} ");
277    cssyyparse(this);
278#ifdef ANDROID_INSTRUMENT
279    android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
280#endif
281    return m_keyframe.release();
282}
283
284static inline bool isColorPropertyID(int propertyId)
285{
286    switch (propertyId) {
287    case CSSPropertyColor:
288    case CSSPropertyBackgroundColor:
289    case CSSPropertyBorderBottomColor:
290    case CSSPropertyBorderLeftColor:
291    case CSSPropertyBorderRightColor:
292    case CSSPropertyBorderTopColor:
293    case CSSPropertyOutlineColor:
294    case CSSPropertyTextLineThroughColor:
295    case CSSPropertyTextOverlineColor:
296    case CSSPropertyTextUnderlineColor:
297    case CSSPropertyWebkitBorderAfterColor:
298    case CSSPropertyWebkitBorderBeforeColor:
299    case CSSPropertyWebkitBorderEndColor:
300    case CSSPropertyWebkitBorderStartColor:
301    case CSSPropertyWebkitColumnRuleColor:
302    case CSSPropertyWebkitTextEmphasisColor:
303    case CSSPropertyWebkitTextFillColor:
304    case CSSPropertyWebkitTextStrokeColor:
305        return true;
306    default:
307        return false;
308    }
309}
310
311static bool parseColorValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important, bool strict)
312{
313    if (!string.length())
314        return false;
315    if (!isColorPropertyID(propertyId))
316        return false;
317    CSSParserString cssString;
318    cssString.characters = const_cast<UChar*>(string.characters());
319    cssString.length = string.length();
320    int valueID = cssValueKeywordID(cssString);
321    bool validPrimitive = false;
322    if (valueID == CSSValueWebkitText)
323        validPrimitive = true;
324    else if (valueID == CSSValueCurrentcolor)
325        validPrimitive = true;
326    else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
327             || (valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText && !strict)) {
328        validPrimitive = true;
329    }
330
331    CSSStyleSheet* stylesheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
332    if (!stylesheet || !stylesheet->document())
333        return false;
334    if (validPrimitive) {
335        CSSProperty property(propertyId, stylesheet->document()->cssPrimitiveValueCache()->createIdentifierValue(valueID), important);
336        declaration->addParsedProperty(property);
337        return true;
338    }
339    RGBA32 color;
340    if (!CSSParser::parseColor(string, color, strict && string[0] != '#'))
341        return false;
342    CSSProperty property(propertyId, stylesheet->document()->cssPrimitiveValueCache()->createColorValue(color), important);
343    declaration->addParsedProperty(property);
344    return true;
345}
346
347static inline bool isSimpleLengthPropertyID(int propertyId, bool& acceptsNegativeNumbers)
348{
349    switch (propertyId) {
350    case CSSPropertyFontSize:
351    case CSSPropertyHeight:
352    case CSSPropertyWidth:
353    case CSSPropertyMinHeight:
354    case CSSPropertyMinWidth:
355    case CSSPropertyPaddingBottom:
356    case CSSPropertyPaddingLeft:
357    case CSSPropertyPaddingRight:
358    case CSSPropertyPaddingTop:
359    case CSSPropertyWebkitLogicalWidth:
360    case CSSPropertyWebkitLogicalHeight:
361    case CSSPropertyWebkitMinLogicalWidth:
362    case CSSPropertyWebkitMinLogicalHeight:
363    case CSSPropertyWebkitPaddingAfter:
364    case CSSPropertyWebkitPaddingBefore:
365    case CSSPropertyWebkitPaddingEnd:
366    case CSSPropertyWebkitPaddingStart:
367        acceptsNegativeNumbers = false;
368        return true;
369    case CSSPropertyBottom:
370    case CSSPropertyLeft:
371    case CSSPropertyMarginBottom:
372    case CSSPropertyMarginLeft:
373    case CSSPropertyMarginRight:
374    case CSSPropertyMarginTop:
375    case CSSPropertyRight:
376    case CSSPropertyTextIndent:
377    case CSSPropertyTop:
378    case CSSPropertyWebkitMarginAfter:
379    case CSSPropertyWebkitMarginBefore:
380    case CSSPropertyWebkitMarginEnd:
381    case CSSPropertyWebkitMarginStart:
382        acceptsNegativeNumbers = true;
383        return true;
384    default:
385        return false;
386    }
387}
388
389static bool parseSimpleLengthValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important, bool strict)
390{
391    const UChar* characters = string.characters();
392    unsigned length = string.length();
393    if (!characters || !length)
394        return false;
395    bool acceptsNegativeNumbers;
396    if (!isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
397        return false;
398
399    CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
400    if (length > 2 && characters[length - 2] == 'p' && characters[length - 1] == 'x') {
401        length -= 2;
402        unit = CSSPrimitiveValue::CSS_PX;
403    } else if (length > 1 && characters[length - 1] == '%') {
404        length -= 1;
405        unit = CSSPrimitiveValue::CSS_PERCENTAGE;
406    }
407
408    // We rely on charactersToDouble for validation as well. The function
409    // will set "ok" to "false" if the entire passed-in character range does
410    // not represent a double.
411    bool ok;
412    double number = charactersToDouble(characters, length, &ok);
413    if (!ok)
414        return false;
415    if (unit == CSSPrimitiveValue::CSS_NUMBER) {
416        if (number && strict)
417            return false;
418        unit = CSSPrimitiveValue::CSS_PX;
419    }
420    if (number < 0 && !acceptsNegativeNumbers)
421        return false;
422
423    CSSStyleSheet* stylesheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
424    if (!stylesheet || !stylesheet->document())
425        return false;
426    CSSProperty property(propertyId, stylesheet->document()->cssPrimitiveValueCache()->createValue(number, unit), important);
427    declaration->addParsedProperty(property);
428    return true;
429}
430
431bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important, bool strict)
432{
433    if (parseSimpleLengthValue(declaration, propertyId, string, important, strict))
434        return true;
435    if (parseColorValue(declaration, propertyId, string, important, strict))
436        return true;
437    CSSParser parser(strict);
438    return parser.parseValue(declaration, propertyId, string, important);
439}
440
441bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important)
442{
443#ifdef ANDROID_INSTRUMENT
444    android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
445#endif
446    ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
447    setStyleSheet(static_cast<CSSStyleSheet*>(declaration->stylesheet()));
448
449    setupParser("@-webkit-value{", string, "} ");
450
451    m_id = propertyId;
452    m_important = important;
453
454    cssyyparse(this);
455
456    m_rule = 0;
457
458    bool ok = false;
459    if (m_hasFontFaceOnlyValues)
460        deleteFontFaceOnlyValues();
461    if (m_numParsedProperties) {
462        ok = true;
463        declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
464        clearProperties();
465    }
466
467#ifdef ANDROID_INSTRUMENT
468    android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
469#endif
470    return ok;
471}
472
473// color will only be changed when string contains a valid css color, making it
474// possible to set up a default color.
475bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
476{
477    // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
478    if (parseColor(string, color, strict))
479        return true;
480
481    CSSParser parser(true);
482    RefPtr<CSSMutableStyleDeclaration> dummyStyleDeclaration = CSSMutableStyleDeclaration::create();
483
484    // Now try to create a color from rgba() syntax.
485    if (!parser.parseColor(dummyStyleDeclaration.get(), string))
486        return false;
487
488    CSSValue* value = parser.m_parsedProperties[0]->value();
489    if (value->cssValueType() != CSSValue::CSS_PRIMITIVE_VALUE)
490        return false;
491
492    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
493    if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_RGBCOLOR)
494        return false;
495
496    color = primitiveValue->getRGBA32Value();
497    return true;
498}
499
500bool CSSParser::parseColor(CSSMutableStyleDeclaration* declaration, const String& string)
501{
502#ifdef ANDROID_INSTRUMENT
503    android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
504#endif
505    ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
506    setStyleSheet(static_cast<CSSStyleSheet*>(declaration->stylesheet()));
507
508    setupParser("@-webkit-decls{color:", string, "} ");
509    cssyyparse(this);
510    m_rule = 0;
511
512#ifdef ANDROID_INSTRUMENT
513    android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
514#endif
515    return (m_numParsedProperties && m_parsedProperties[0]->m_id == CSSPropertyColor);
516}
517
518bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document)
519{
520    if (!document || !document->page())
521        return false;
522
523    CSSParserString cssColor;
524    cssColor.characters = const_cast<UChar*>(string.characters());
525    cssColor.length = string.length();
526    int id = cssValueKeywordID(cssColor);
527    if (id <= 0)
528        return false;
529
530    color = document->page()->theme()->systemColor(id).rgb();
531    return true;
532}
533
534void CSSParser::parseSelector(const String& string, Document* doc, CSSSelectorList& selectorList)
535{
536#ifdef ANDROID_INSTRUMENT
537    android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
538#endif
539    RefPtr<CSSStyleSheet> dummyStyleSheet = CSSStyleSheet::create(doc);
540
541    setStyleSheet(dummyStyleSheet.get());
542    m_selectorListForParseSelector = &selectorList;
543
544    setupParser("@-webkit-selector{", string, "}");
545
546    cssyyparse(this);
547
548    m_selectorListForParseSelector = 0;
549
550    // The style sheet will be deleted right away, so it won't outlive the document.
551    ASSERT(dummyStyleSheet->hasOneRef());
552
553#ifdef ANDROID_INSTRUMENT
554    android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
555#endif
556}
557
558bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration* declaration, const String& string, RefPtr<CSSStyleSourceData>* styleSourceData)
559{
560#ifdef ANDROID_INSTRUMENT
561    android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
562#endif
563
564    // Length of the "@-webkit-decls{" prefix.
565    static const unsigned prefixLength = 15;
566
567    ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
568    setStyleSheet(static_cast<CSSStyleSheet*>(declaration->stylesheet()));
569    if (styleSourceData) {
570        m_currentRuleData = CSSRuleSourceData::create();
571        m_currentRuleData->styleSourceData = CSSStyleSourceData::create();
572        m_inStyleRuleOrDeclaration = true;
573    }
574
575    setupParser("@-webkit-decls{", string, "} ");
576    cssyyparse(this);
577    m_rule = 0;
578
579    bool ok = false;
580    if (m_hasFontFaceOnlyValues)
581        deleteFontFaceOnlyValues();
582    if (m_numParsedProperties) {
583        ok = true;
584        declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
585        clearProperties();
586    }
587
588    if (m_currentRuleData) {
589        m_currentRuleData->styleSourceData->styleBodyRange.start = 0;
590        m_currentRuleData->styleSourceData->styleBodyRange.end = string.length();
591        for (Vector<CSSPropertySourceData>::iterator it = m_currentRuleData->styleSourceData->propertyData.begin(), endIt = m_currentRuleData->styleSourceData->propertyData.end(); it != endIt; ++it) {
592            (*it).range.start -= prefixLength;
593            (*it).range.end -= prefixLength;
594        }
595    }
596
597    if (styleSourceData) {
598        *styleSourceData = m_currentRuleData->styleSourceData.release();
599        m_currentRuleData = 0;
600        m_inStyleRuleOrDeclaration = false;
601    }
602#ifdef ANDROID_INSTRUMENT
603    android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
604#endif
605    return ok;
606}
607
608bool CSSParser::parseMediaQuery(MediaList* queries, const String& string)
609{
610    if (string.isEmpty())
611        return true;
612
613#ifdef ANDROID_INSTRUMENT
614    android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
615#endif
616    ASSERT(!m_mediaQuery);
617
618    // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
619    // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
620    setupParser("@-webkit-mediaquery ", string, "} ");
621    cssyyparse(this);
622
623    bool ok = false;
624    if (m_mediaQuery) {
625        ok = true;
626        queries->appendMediaQuery(m_mediaQuery.release());
627    }
628
629#ifdef ANDROID_INSTRUMENT
630    android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
631#endif
632    return ok;
633}
634
635
636void CSSParser::addProperty(int propId, PassRefPtr<CSSValue> value, bool important)
637{
638    OwnPtr<CSSProperty> prop(new CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand));
639    if (m_numParsedProperties >= m_maxParsedProperties) {
640        m_maxParsedProperties += 32;
641        if (m_maxParsedProperties > UINT_MAX / sizeof(CSSProperty*))
642            return;
643        m_parsedProperties = static_cast<CSSProperty**>(fastRealloc(m_parsedProperties,
644            m_maxParsedProperties * sizeof(CSSProperty*)));
645    }
646    m_parsedProperties[m_numParsedProperties++] = prop.leakPtr();
647}
648
649void CSSParser::rollbackLastProperties(int num)
650{
651    ASSERT(num >= 0);
652    ASSERT(m_numParsedProperties >= static_cast<unsigned>(num));
653
654    for (int i = 0; i < num; ++i)
655        delete m_parsedProperties[--m_numParsedProperties];
656}
657
658void CSSParser::clearProperties()
659{
660    for (unsigned i = 0; i < m_numParsedProperties; i++)
661        delete m_parsedProperties[i];
662    m_numParsedProperties = 0;
663    m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
664    m_hasFontFaceOnlyValues = false;
665}
666
667void CSSParser::setStyleSheet(CSSStyleSheet* styleSheet)
668{
669    m_styleSheet = styleSheet;
670    m_primitiveValueCache = document() ? document()->cssPrimitiveValueCache() : CSSPrimitiveValueCache::create();
671}
672
673Document* CSSParser::document() const
674{
675    StyleBase* root = m_styleSheet;
676    while (root && root->parent())
677        root = root->parent();
678    if (!root)
679        return 0;
680    if (!root->isCSSStyleSheet())
681        return 0;
682    return static_cast<CSSStyleSheet*>(root)->document();
683}
684
685bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, bool strict)
686{
687    bool b = false;
688    switch (value->unit) {
689    case CSSPrimitiveValue::CSS_NUMBER:
690        b = (unitflags & FNumber);
691        if (!b && ((unitflags & (FLength | FAngle | FTime)) && (value->fValue == 0 || !strict))) {
692            value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
693                          ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
694            b = true;
695        }
696        if (!b && (unitflags & FInteger) && value->isInt)
697            b = true;
698        break;
699    case CSSPrimitiveValue::CSS_PERCENTAGE:
700        b = (unitflags & FPercent);
701        break;
702    case CSSParserValue::Q_EMS:
703    case CSSPrimitiveValue::CSS_EMS:
704    case CSSPrimitiveValue::CSS_REMS:
705    case CSSPrimitiveValue::CSS_EXS:
706    case CSSPrimitiveValue::CSS_PX:
707    case CSSPrimitiveValue::CSS_CM:
708    case CSSPrimitiveValue::CSS_MM:
709    case CSSPrimitiveValue::CSS_IN:
710    case CSSPrimitiveValue::CSS_PT:
711    case CSSPrimitiveValue::CSS_PC:
712        b = (unitflags & FLength);
713        break;
714    case CSSPrimitiveValue::CSS_MS:
715    case CSSPrimitiveValue::CSS_S:
716        b = (unitflags & FTime);
717        break;
718    case CSSPrimitiveValue::CSS_DEG:
719    case CSSPrimitiveValue::CSS_RAD:
720    case CSSPrimitiveValue::CSS_GRAD:
721    case CSSPrimitiveValue::CSS_TURN:
722        b = (unitflags & FAngle);
723        break;
724    case CSSPrimitiveValue::CSS_HZ:
725    case CSSPrimitiveValue::CSS_KHZ:
726    case CSSPrimitiveValue::CSS_DIMENSION:
727    default:
728        break;
729    }
730    if (b && unitflags & FNonNeg && value->fValue < 0)
731        b = false;
732    return b;
733}
734
735static int unitFromString(CSSParserValue* value)
736{
737    if (value->unit != CSSPrimitiveValue::CSS_IDENT || value->id)
738        return 0;
739
740    if (equal(value->string, "em"))
741        return CSSPrimitiveValue::CSS_EMS;
742    if (equal(value->string, "rem"))
743        return CSSPrimitiveValue::CSS_REMS;
744    if (equal(value->string, "ex"))
745        return CSSPrimitiveValue::CSS_EXS;
746    if (equal(value->string, "px"))
747        return CSSPrimitiveValue::CSS_PX;
748    if (equal(value->string, "cm"))
749        return CSSPrimitiveValue::CSS_CM;
750    if (equal(value->string, "mm"))
751        return CSSPrimitiveValue::CSS_MM;
752    if (equal(value->string, "in"))
753        return CSSPrimitiveValue::CSS_IN;
754    if (equal(value->string, "pt"))
755        return CSSPrimitiveValue::CSS_PT;
756    if (equal(value->string, "pc"))
757        return CSSPrimitiveValue::CSS_PC;
758    if (equal(value->string, "deg"))
759        return CSSPrimitiveValue::CSS_DEG;
760    if (equal(value->string, "rad"))
761        return CSSPrimitiveValue::CSS_RAD;
762    if (equal(value->string, "grad"))
763        return CSSPrimitiveValue::CSS_GRAD;
764    if (equal(value->string, "turn"))
765        return CSSPrimitiveValue::CSS_TURN;
766    if (equal(value->string, "ms"))
767        return CSSPrimitiveValue::CSS_MS;
768    if (equal(value->string, "s"))
769        return CSSPrimitiveValue::CSS_S;
770    if (equal(value->string, "Hz"))
771        return CSSPrimitiveValue::CSS_HZ;
772    if (equal(value->string, "kHz"))
773        return CSSPrimitiveValue::CSS_KHZ;
774
775    return 0;
776}
777
778void CSSParser::checkForOrphanedUnits()
779{
780    if (m_strict || inShorthand())
781        return;
782
783    // The purpose of this code is to implement the WinIE quirk that allows unit types to be separated from their numeric values
784    // by whitespace, so e.g., width: 20 px instead of width:20px.  This is invalid CSS, so we don't do this in strict mode.
785    CSSParserValue* numericVal = 0;
786    unsigned size = m_valueList->size();
787    for (unsigned i = 0; i < size; i++) {
788        CSSParserValue* value = m_valueList->valueAt(i);
789
790        if (numericVal) {
791            // Change the unit type of the numeric val to match.
792            int unit = unitFromString(value);
793            if (unit) {
794                numericVal->unit = unit;
795                numericVal = 0;
796
797                // Now delete the bogus unit value.
798                m_valueList->deleteValueAt(i);
799                i--; // We're safe even though |i| is unsigned, since we only hit this code if we had a previous numeric value (so |i| is always > 0 here).
800                size--;
801                continue;
802            }
803        }
804
805        numericVal = (value->unit == CSSPrimitiveValue::CSS_NUMBER) ? value : 0;
806    }
807}
808
809bool CSSParser::parseValue(int propId, bool important)
810{
811    if (!m_valueList)
812        return false;
813
814    CSSParserValue* value = m_valueList->current();
815
816    if (!value)
817        return false;
818
819    int id = value->id;
820
821    // In quirks mode, we will look for units that have been incorrectly separated from the number they belong to
822    // by a space.  We go ahead and associate the unit with the number even though it is invalid CSS.
823    checkForOrphanedUnits();
824
825    int num = inShorthand() ? 1 : m_valueList->size();
826
827    if (id == CSSValueInherit) {
828        if (num != 1)
829            return false;
830        addProperty(propId, CSSInheritedValue::create(), important);
831        return true;
832    }
833    else if (id == CSSValueInitial) {
834        if (num != 1)
835            return false;
836        addProperty(propId, CSSInitialValue::createExplicit(), important);
837        return true;
838    }
839
840    bool validPrimitive = false;
841    RefPtr<CSSValue> parsedValue;
842
843    switch (static_cast<CSSPropertyID>(propId)) {
844        /* The comment to the left defines all valid value of this properties as defined
845         * in CSS 2, Appendix F. Property index
846         */
847
848        /* All the CSS properties are not supported by the renderer at the moment.
849         * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
850         * (see parseAuralValues). As we don't support them at all this seems reasonable.
851         */
852
853    case CSSPropertySize:                 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
854        return parseSize(propId, important);
855
856    case CSSPropertyQuotes:               // [<string> <string>]+ | none | inherit
857        if (id)
858            validPrimitive = true;
859        else
860            return parseQuotes(propId, important);
861        break;
862    case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | inherit
863        if (id == CSSValueNormal
864            || id == CSSValueEmbed
865            || id == CSSValueBidiOverride
866            || id == CSSValueWebkitIsolate)
867            validPrimitive = true;
868        break;
869
870    case CSSPropertyPosition:             // static | relative | absolute | fixed | inherit
871        if (id == CSSValueStatic ||
872             id == CSSValueRelative ||
873             id == CSSValueAbsolute ||
874             id == CSSValueFixed)
875            validPrimitive = true;
876        break;
877
878    case CSSPropertyPageBreakAfter:     // auto | always | avoid | left | right | inherit
879    case CSSPropertyPageBreakBefore:
880    case CSSPropertyWebkitColumnBreakAfter:
881    case CSSPropertyWebkitColumnBreakBefore:
882        if (id == CSSValueAuto ||
883             id == CSSValueAlways ||
884             id == CSSValueAvoid ||
885             id == CSSValueLeft ||
886             id == CSSValueRight)
887            validPrimitive = true;
888        break;
889
890    case CSSPropertyPageBreakInside:    // avoid | auto | inherit
891    case CSSPropertyWebkitColumnBreakInside:
892        if (id == CSSValueAuto || id == CSSValueAvoid)
893            validPrimitive = true;
894        break;
895
896    case CSSPropertyEmptyCells:          // show | hide | inherit
897        if (id == CSSValueShow ||
898             id == CSSValueHide)
899            validPrimitive = true;
900        break;
901
902    case CSSPropertyContent:              // [ <string> | <uri> | <counter> | attr(X) | open-quote |
903        // close-quote | no-open-quote | no-close-quote ]+ | inherit
904        return parseContent(propId, important);
905
906    case CSSPropertyWhiteSpace:          // normal | pre | nowrap | inherit
907        if (id == CSSValueNormal ||
908            id == CSSValuePre ||
909            id == CSSValuePreWrap ||
910            id == CSSValuePreLine ||
911            id == CSSValueNowrap)
912            validPrimitive = true;
913        break;
914
915    case CSSPropertyClip:                 // <shape> | auto | inherit
916        if (id == CSSValueAuto)
917            validPrimitive = true;
918        else if (value->unit == CSSParserValue::Function)
919            return parseShape(propId, important);
920        break;
921
922    /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
923     * correctly and allows optimization in WebCore::applyRule(..)
924     */
925    case CSSPropertyCaptionSide:         // top | bottom | left | right | inherit
926        if (id == CSSValueLeft || id == CSSValueRight ||
927            id == CSSValueTop || id == CSSValueBottom)
928            validPrimitive = true;
929        break;
930
931    case CSSPropertyBorderCollapse:      // collapse | separate | inherit
932        if (id == CSSValueCollapse || id == CSSValueSeparate)
933            validPrimitive = true;
934        break;
935
936    case CSSPropertyVisibility:           // visible | hidden | collapse | inherit
937        if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueCollapse)
938            validPrimitive = true;
939        break;
940
941    case CSSPropertyOverflow: {
942        ShorthandScope scope(this, propId);
943        if (num != 1 || !parseValue(CSSPropertyOverflowX, important))
944            return false;
945        CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value();
946        addProperty(CSSPropertyOverflowY, value, important);
947        return true;
948    }
949    case CSSPropertyOverflowX:
950    case CSSPropertyOverflowY:           // visible | hidden | scroll | auto | marquee | overlay | inherit
951        if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueScroll || id == CSSValueAuto ||
952            id == CSSValueOverlay || id == CSSValueWebkitMarquee)
953            validPrimitive = true;
954        break;
955
956    case CSSPropertyListStylePosition:  // inside | outside | inherit
957        if (id == CSSValueInside || id == CSSValueOutside)
958            validPrimitive = true;
959        break;
960
961    case CSSPropertyListStyleType:
962        // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
963        // for the list of supported list-style-types.
964        if ((id >= CSSValueDisc && id <= CSSValueKatakanaIroha) || id == CSSValueNone)
965            validPrimitive = true;
966        break;
967
968    case CSSPropertyDisplay:
969        // inline | block | list-item | run-in | inline-block | table |
970        // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
971        // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit
972#if ENABLE(WCSS)
973        if ((id >= CSSValueInline && id <= CSSValueWapMarquee) || id == CSSValueNone)
974#else
975        if ((id >= CSSValueInline && id <= CSSValueWebkitInlineBox) || id == CSSValueNone)
976#endif
977            validPrimitive = true;
978        break;
979
980    case CSSPropertyDirection:            // ltr | rtl | inherit
981        if (id == CSSValueLtr || id == CSSValueRtl)
982            validPrimitive = true;
983        break;
984
985    case CSSPropertyTextTransform:       // capitalize | uppercase | lowercase | none | inherit
986        if ((id >= CSSValueCapitalize && id <= CSSValueLowercase) || id == CSSValueNone)
987            validPrimitive = true;
988        break;
989
990    case CSSPropertyFloat:                // left | right | none | inherit + center for buggy CSS
991        if (id == CSSValueLeft || id == CSSValueRight ||
992             id == CSSValueNone || id == CSSValueCenter)
993            validPrimitive = true;
994        break;
995
996    case CSSPropertyClear:                // none | left | right | both | inherit
997        if (id == CSSValueNone || id == CSSValueLeft ||
998             id == CSSValueRight|| id == CSSValueBoth)
999            validPrimitive = true;
1000        break;
1001
1002    case CSSPropertyTextAlign:
1003        // left | right | center | justify | webkit_left | webkit_right | webkit_center | webkit_match_parent |
1004        // start | end | <string> | inherit
1005        if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
1006             || value->unit == CSSPrimitiveValue::CSS_STRING)
1007            validPrimitive = true;
1008        break;
1009
1010    case CSSPropertyOutlineStyle:        // (<border-style> except hidden) | auto | inherit
1011        if (id == CSSValueAuto || id == CSSValueNone || (id >= CSSValueInset && id <= CSSValueDouble))
1012            validPrimitive = true;
1013        break;
1014
1015    case CSSPropertyBorderTopStyle:     //// <border-style> | inherit
1016    case CSSPropertyBorderRightStyle:   //   Defined as:    none | hidden | dotted | dashed |
1017    case CSSPropertyBorderBottomStyle:  //   solid | double | groove | ridge | inset | outset
1018    case CSSPropertyBorderLeftStyle:
1019    case CSSPropertyWebkitBorderStartStyle:
1020    case CSSPropertyWebkitBorderEndStyle:
1021    case CSSPropertyWebkitBorderBeforeStyle:
1022    case CSSPropertyWebkitBorderAfterStyle:
1023    case CSSPropertyWebkitColumnRuleStyle:
1024        if (id >= CSSValueNone && id <= CSSValueDouble)
1025            validPrimitive = true;
1026        break;
1027
1028    case CSSPropertyFontWeight:  // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
1029        return parseFontWeight(important);
1030
1031    case CSSPropertyBorderSpacing: {
1032        const int properties[2] = { CSSPropertyWebkitBorderHorizontalSpacing,
1033                                    CSSPropertyWebkitBorderVerticalSpacing };
1034        if (num == 1) {
1035            ShorthandScope scope(this, CSSPropertyBorderSpacing);
1036            if (!parseValue(properties[0], important))
1037                return false;
1038            CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value();
1039            addProperty(properties[1], value, important);
1040            return true;
1041        }
1042        else if (num == 2) {
1043            ShorthandScope scope(this, CSSPropertyBorderSpacing);
1044            if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
1045                return false;
1046            return true;
1047        }
1048        return false;
1049    }
1050    case CSSPropertyWebkitBorderHorizontalSpacing:
1051    case CSSPropertyWebkitBorderVerticalSpacing:
1052        validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
1053        break;
1054    case CSSPropertyOutlineColor:        // <color> | invert | inherit
1055        // Outline color has "invert" as additional keyword.
1056        // Also, we want to allow the special focus color even in strict parsing mode.
1057        if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
1058            validPrimitive = true;
1059            break;
1060        }
1061        /* nobreak */
1062    case CSSPropertyBackgroundColor: // <color> | inherit
1063    case CSSPropertyBorderTopColor: // <color> | inherit
1064    case CSSPropertyBorderRightColor:
1065    case CSSPropertyBorderBottomColor:
1066    case CSSPropertyBorderLeftColor:
1067    case CSSPropertyWebkitBorderStartColor:
1068    case CSSPropertyWebkitBorderEndColor:
1069    case CSSPropertyWebkitBorderBeforeColor:
1070    case CSSPropertyWebkitBorderAfterColor:
1071    case CSSPropertyColor: // <color> | inherit
1072    case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors
1073    case CSSPropertyTextUnderlineColor:
1074    case CSSPropertyTextOverlineColor:
1075    case CSSPropertyWebkitColumnRuleColor:
1076    case CSSPropertyWebkitTextEmphasisColor:
1077    case CSSPropertyWebkitTextFillColor:
1078    case CSSPropertyWebkitTextStrokeColor:
1079        if (id == CSSValueWebkitText)
1080            validPrimitive = true; // Always allow this, even when strict parsing is on,
1081                                    // since we use this in our UA sheets.
1082        else if (id == CSSValueCurrentcolor)
1083            validPrimitive = true;
1084        else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu ||
1085             (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && !m_strict)) {
1086            validPrimitive = true;
1087        } else {
1088            parsedValue = parseColor();
1089            if (parsedValue)
1090                m_valueList->next();
1091        }
1092        break;
1093
1094    case CSSPropertyCursor: {
1095        // [<uri>,]*  [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
1096        // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
1097        // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
1098        // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
1099        // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
1100        RefPtr<CSSValueList> list;
1101        while (value && value->unit == CSSPrimitiveValue::CSS_URI) {
1102            if (!list)
1103                list = CSSValueList::createCommaSeparated();
1104            String uri = value->string;
1105            Vector<int> coords;
1106            value = m_valueList->next();
1107            while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
1108                coords.append(int(value->fValue));
1109                value = m_valueList->next();
1110            }
1111            IntPoint hotSpot(-1, -1);
1112            int nrcoords = coords.size();
1113            if (nrcoords > 0 && nrcoords != 2)
1114                return false;
1115            if (nrcoords == 2)
1116                hotSpot = IntPoint(coords[0], coords[1]);
1117
1118            if (!uri.isNull() && m_styleSheet) {
1119                // FIXME: The completeURL call should be done when using the CSSCursorImageValue,
1120                // not when creating it.
1121                list->append(CSSCursorImageValue::create(m_styleSheet->completeURL(uri), hotSpot));
1122            }
1123
1124            if ((m_strict && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ',')))
1125                return false;
1126            value = m_valueList->next(); // comma
1127        }
1128        if (list) {
1129            if (!value) { // no value after url list (MSIE 5 compatibility)
1130                if (list->length() != 1)
1131                    return false;
1132            } else if (!m_strict && value->id == CSSValueHand) // MSIE 5 compatibility :/
1133                list->append(primitiveValueCache()->createIdentifierValue(CSSValuePointer));
1134            else if (value && ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone))
1135                list->append(primitiveValueCache()->createIdentifierValue(value->id));
1136            m_valueList->next();
1137            parsedValue = list.release();
1138            break;
1139        }
1140        id = value->id;
1141        if (!m_strict && value->id == CSSValueHand) { // MSIE 5 compatibility :/
1142            id = CSSValuePointer;
1143            validPrimitive = true;
1144        } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
1145            validPrimitive = true;
1146        break;
1147    }
1148
1149    case CSSPropertyBackgroundAttachment:
1150    case CSSPropertyBackgroundClip:
1151    case CSSPropertyWebkitBackgroundClip:
1152    case CSSPropertyWebkitBackgroundComposite:
1153    case CSSPropertyBackgroundImage:
1154    case CSSPropertyBackgroundOrigin:
1155    case CSSPropertyWebkitBackgroundOrigin:
1156    case CSSPropertyBackgroundPosition:
1157    case CSSPropertyBackgroundPositionX:
1158    case CSSPropertyBackgroundPositionY:
1159    case CSSPropertyBackgroundSize:
1160    case CSSPropertyWebkitBackgroundSize:
1161    case CSSPropertyBackgroundRepeat:
1162    case CSSPropertyBackgroundRepeatX:
1163    case CSSPropertyBackgroundRepeatY:
1164    case CSSPropertyWebkitMaskAttachment:
1165    case CSSPropertyWebkitMaskClip:
1166    case CSSPropertyWebkitMaskComposite:
1167    case CSSPropertyWebkitMaskImage:
1168    case CSSPropertyWebkitMaskOrigin:
1169    case CSSPropertyWebkitMaskPosition:
1170    case CSSPropertyWebkitMaskPositionX:
1171    case CSSPropertyWebkitMaskPositionY:
1172    case CSSPropertyWebkitMaskSize:
1173    case CSSPropertyWebkitMaskRepeat:
1174    case CSSPropertyWebkitMaskRepeatX:
1175    case CSSPropertyWebkitMaskRepeatY: {
1176        RefPtr<CSSValue> val1;
1177        RefPtr<CSSValue> val2;
1178        int propId1, propId2;
1179        bool result = false;
1180        if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
1181            OwnPtr<ShorthandScope> shorthandScope;
1182            if (propId == CSSPropertyBackgroundPosition ||
1183                propId == CSSPropertyBackgroundRepeat ||
1184                propId == CSSPropertyWebkitMaskPosition ||
1185                propId == CSSPropertyWebkitMaskRepeat) {
1186                shorthandScope.set(new ShorthandScope(this, propId));
1187            }
1188            addProperty(propId1, val1.release(), important);
1189            if (val2)
1190                addProperty(propId2, val2.release(), important);
1191            result = true;
1192        }
1193        m_implicitShorthand = false;
1194        return result;
1195    }
1196    case CSSPropertyListStyleImage:     // <uri> | none | inherit
1197        if (id == CSSValueNone) {
1198            parsedValue = CSSImageValue::create();
1199            m_valueList->next();
1200        } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
1201            if (m_styleSheet) {
1202                // FIXME: The completeURL call should be done when using the CSSImageValue,
1203                // not when creating it.
1204                parsedValue = CSSImageValue::create(m_styleSheet->completeURL(value->string));
1205                m_valueList->next();
1206            }
1207        } else if (isGeneratedImageValue(value)) {
1208            if (parseGeneratedImage(parsedValue))
1209                m_valueList->next();
1210            else
1211                return false;
1212        }
1213        break;
1214
1215    case CSSPropertyWebkitTextStrokeWidth:
1216    case CSSPropertyOutlineWidth:        // <border-width> | inherit
1217    case CSSPropertyBorderTopWidth:     //// <border-width> | inherit
1218    case CSSPropertyBorderRightWidth:   //   Which is defined as
1219    case CSSPropertyBorderBottomWidth:  //   thin | medium | thick | <length>
1220    case CSSPropertyBorderLeftWidth:
1221    case CSSPropertyWebkitBorderStartWidth:
1222    case CSSPropertyWebkitBorderEndWidth:
1223    case CSSPropertyWebkitBorderBeforeWidth:
1224    case CSSPropertyWebkitBorderAfterWidth:
1225    case CSSPropertyWebkitColumnRuleWidth:
1226        if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
1227            validPrimitive = true;
1228        else
1229            validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
1230        break;
1231
1232    case CSSPropertyLetterSpacing:       // normal | <length> | inherit
1233    case CSSPropertyWordSpacing:         // normal | <length> | inherit
1234        if (id == CSSValueNormal)
1235            validPrimitive = true;
1236        else
1237            validPrimitive = validUnit(value, FLength, m_strict);
1238        break;
1239
1240    case CSSPropertyWordBreak:          // normal | break-all | break-word (this is a custom extension)
1241        if (id == CSSValueNormal || id == CSSValueBreakAll || id == CSSValueBreakWord)
1242            validPrimitive = true;
1243        break;
1244
1245    case CSSPropertyWordWrap:           // normal | break-word
1246        if (id == CSSValueNormal || id == CSSValueBreakWord)
1247            validPrimitive = true;
1248        break;
1249    case CSSPropertySpeak:           // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit
1250        if (id == CSSValueNone || id == CSSValueNormal || id == CSSValueSpellOut || id == CSSValueDigits
1251            || id == CSSValueLiteralPunctuation || id == CSSValueNoPunctuation)
1252            validPrimitive = true;
1253        break;
1254
1255    case CSSPropertyTextIndent:          // <length> | <percentage> | inherit
1256        validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
1257        break;
1258
1259    case CSSPropertyPaddingTop:          //// <padding-width> | inherit
1260    case CSSPropertyPaddingRight:        //   Which is defined as
1261    case CSSPropertyPaddingBottom:       //   <length> | <percentage>
1262    case CSSPropertyPaddingLeft:         ////
1263    case CSSPropertyWebkitPaddingStart:
1264    case CSSPropertyWebkitPaddingEnd:
1265    case CSSPropertyWebkitPaddingBefore:
1266    case CSSPropertyWebkitPaddingAfter:
1267        validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
1268        break;
1269
1270    case CSSPropertyMaxHeight:           // <length> | <percentage> | none | inherit
1271    case CSSPropertyMaxWidth:            // <length> | <percentage> | none | inherit
1272    case CSSPropertyWebkitMaxLogicalWidth:
1273    case CSSPropertyWebkitMaxLogicalHeight:
1274        if (id == CSSValueNone || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) {
1275            validPrimitive = true;
1276            break;
1277        }
1278        /* nobreak */
1279    case CSSPropertyMinHeight:           // <length> | <percentage> | inherit
1280    case CSSPropertyMinWidth:            // <length> | <percentage> | inherit
1281    case CSSPropertyWebkitMinLogicalWidth:
1282    case CSSPropertyWebkitMinLogicalHeight:
1283        if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
1284            validPrimitive = true;
1285        else
1286            validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
1287        break;
1288
1289    case CSSPropertyFontSize:
1290        // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
1291        if (id >= CSSValueXxSmall && id <= CSSValueLarger)
1292            validPrimitive = true;
1293        else
1294            validPrimitive = (validUnit(value, FLength | FPercent | FNonNeg, m_strict));
1295        break;
1296
1297    case CSSPropertyFontStyle:           // normal | italic | oblique | inherit
1298        return parseFontStyle(important);
1299
1300    case CSSPropertyFontVariant:         // normal | small-caps | inherit
1301        return parseFontVariant(important);
1302
1303    case CSSPropertyVerticalAlign:
1304        // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
1305        // <percentage> | <length> | inherit
1306
1307        if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
1308            validPrimitive = true;
1309        else
1310            validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
1311        break;
1312
1313    case CSSPropertyHeight:               // <length> | <percentage> | auto | inherit
1314    case CSSPropertyWidth:                // <length> | <percentage> | auto | inherit
1315    case CSSPropertyWebkitLogicalWidth:
1316    case CSSPropertyWebkitLogicalHeight:
1317        if (id == CSSValueAuto || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
1318            validPrimitive = true;
1319        else
1320            // ### handle multilength case where we allow relative units
1321            validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
1322        break;
1323
1324    case CSSPropertyBottom:               // <length> | <percentage> | auto | inherit
1325    case CSSPropertyLeft:                 // <length> | <percentage> | auto | inherit
1326    case CSSPropertyRight:                // <length> | <percentage> | auto | inherit
1327    case CSSPropertyTop:                  // <length> | <percentage> | auto | inherit
1328    case CSSPropertyMarginTop:           //// <margin-width> | inherit
1329    case CSSPropertyMarginRight:         //   Which is defined as
1330    case CSSPropertyMarginBottom:        //   <length> | <percentage> | auto | inherit
1331    case CSSPropertyMarginLeft:          ////
1332    case CSSPropertyWebkitMarginStart:
1333    case CSSPropertyWebkitMarginEnd:
1334    case CSSPropertyWebkitMarginBefore:
1335    case CSSPropertyWebkitMarginAfter:
1336        if (id == CSSValueAuto)
1337            validPrimitive = true;
1338        else
1339            validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
1340        break;
1341
1342    case CSSPropertyZIndex:              // auto | <integer> | inherit
1343        if (id == CSSValueAuto) {
1344            validPrimitive = true;
1345            break;
1346        }
1347        /* nobreak */
1348    case CSSPropertyOrphans:              // <integer> | inherit
1349    case CSSPropertyWidows:               // <integer> | inherit
1350        // ### not supported later on
1351        validPrimitive = (!id && validUnit(value, FInteger, false));
1352        break;
1353
1354    case CSSPropertyLineHeight:          // normal | <number> | <length> | <percentage> | inherit
1355        if (id == CSSValueNormal)
1356            validPrimitive = true;
1357        else
1358            validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict));
1359        break;
1360    case CSSPropertyCounterIncrement:    // [ <identifier> <integer>? ]+ | none | inherit
1361        if (id != CSSValueNone)
1362            return parseCounter(propId, 1, important);
1363        validPrimitive = true;
1364        break;
1365     case CSSPropertyCounterReset:        // [ <identifier> <integer>? ]+ | none | inherit
1366        if (id != CSSValueNone)
1367            return parseCounter(propId, 0, important);
1368        validPrimitive = true;
1369        break;
1370    case CSSPropertyFontFamily:
1371        // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
1372    {
1373        parsedValue = parseFontFamily();
1374        break;
1375    }
1376
1377    case CSSPropertyTextDecoration:
1378    case CSSPropertyWebkitTextDecorationsInEffect:
1379        // none | [ underline || overline || line-through || blink ] | inherit
1380        if (id == CSSValueNone) {
1381            validPrimitive = true;
1382        } else {
1383            RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
1384            bool isValid = true;
1385            while (isValid && value) {
1386                switch (value->id) {
1387                case CSSValueBlink:
1388                    break;
1389                case CSSValueUnderline:
1390                case CSSValueOverline:
1391                case CSSValueLineThrough:
1392                    list->append(primitiveValueCache()->createIdentifierValue(value->id));
1393                    break;
1394                default:
1395                    isValid = false;
1396                }
1397                value = m_valueList->next();
1398            }
1399            if (list->length() && isValid) {
1400                parsedValue = list.release();
1401                m_valueList->next();
1402            }
1403        }
1404        break;
1405
1406    case CSSPropertyZoom:          // normal | reset | document | <number> | <percentage> | inherit
1407        if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
1408            validPrimitive = true;
1409        else
1410            validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, true));
1411        break;
1412
1413    case CSSPropertyTableLayout:         // auto | fixed | inherit
1414        if (id == CSSValueAuto || id == CSSValueFixed)
1415            validPrimitive = true;
1416        break;
1417
1418    case CSSPropertySrc:  // Only used within @font-face, so cannot use inherit | initial or be !important.  This is a list of urls or local references.
1419        return parseFontFaceSrc();
1420
1421    case CSSPropertyUnicodeRange:
1422        return parseFontFaceUnicodeRange();
1423
1424    /* CSS3 properties */
1425    case CSSPropertyWebkitAppearance:
1426        if ((id >= CSSValueCheckbox && id <= CSSValueTextarea) || id == CSSValueNone)
1427            validPrimitive = true;
1428        break;
1429
1430    case CSSPropertyWebkitBorderImage:
1431    case CSSPropertyWebkitMaskBoxImage:
1432        if (id == CSSValueNone)
1433            validPrimitive = true;
1434        else {
1435            RefPtr<CSSValue> result;
1436            if (parseBorderImage(propId, important, result)) {
1437                addProperty(propId, result, important);
1438                return true;
1439            }
1440        }
1441        break;
1442    case CSSPropertyBorderTopRightRadius:
1443    case CSSPropertyBorderTopLeftRadius:
1444    case CSSPropertyBorderBottomLeftRadius:
1445    case CSSPropertyBorderBottomRightRadius: {
1446        if (num != 1 && num != 2)
1447            return false;
1448        validPrimitive = validUnit(value, FLength | FPercent, m_strict);
1449        if (!validPrimitive)
1450            return false;
1451        RefPtr<CSSPrimitiveValue> parsedValue1 = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1452        RefPtr<CSSPrimitiveValue> parsedValue2;
1453        if (num == 2) {
1454            value = m_valueList->next();
1455            validPrimitive = validUnit(value, FLength | FPercent, m_strict);
1456            if (!validPrimitive)
1457                return false;
1458            parsedValue2 = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1459        } else
1460            parsedValue2 = parsedValue1;
1461
1462        RefPtr<Pair> pair = Pair::create(parsedValue1.release(), parsedValue2.release());
1463        RefPtr<CSSPrimitiveValue> val = primitiveValueCache()->createValue(pair.release());
1464        addProperty(propId, val.release(), important);
1465        return true;
1466    }
1467    case CSSPropertyBorderRadius:
1468    case CSSPropertyWebkitBorderRadius:
1469        return parseBorderRadius(propId, important);
1470    case CSSPropertyOutlineOffset:
1471        validPrimitive = validUnit(value, FLength | FPercent, m_strict);
1472        break;
1473    case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
1474    case CSSPropertyBoxShadow:
1475    case CSSPropertyWebkitBoxShadow:
1476        if (id == CSSValueNone)
1477            validPrimitive = true;
1478        else
1479            return parseShadow(propId, important);
1480        break;
1481    case CSSPropertyWebkitBoxReflect:
1482        if (id == CSSValueNone)
1483            validPrimitive = true;
1484        else
1485            return parseReflect(propId, important);
1486        break;
1487    case CSSPropertyOpacity:
1488        validPrimitive = validUnit(value, FNumber, m_strict);
1489        break;
1490    case CSSPropertyWebkitBoxAlign:
1491        if (id == CSSValueStretch || id == CSSValueStart || id == CSSValueEnd ||
1492            id == CSSValueCenter || id == CSSValueBaseline)
1493            validPrimitive = true;
1494        break;
1495    case CSSPropertyWebkitBoxDirection:
1496        if (id == CSSValueNormal || id == CSSValueReverse)
1497            validPrimitive = true;
1498        break;
1499    case CSSPropertyWebkitBoxLines:
1500        if (id == CSSValueSingle || id == CSSValueMultiple)
1501            validPrimitive = true;
1502        break;
1503    case CSSPropertyWebkitBoxOrient:
1504        if (id == CSSValueHorizontal || id == CSSValueVertical ||
1505            id == CSSValueInlineAxis || id == CSSValueBlockAxis)
1506            validPrimitive = true;
1507        break;
1508    case CSSPropertyWebkitBoxPack:
1509        if (id == CSSValueStart || id == CSSValueEnd ||
1510            id == CSSValueCenter || id == CSSValueJustify)
1511            validPrimitive = true;
1512        break;
1513    case CSSPropertyWebkitBoxFlex:
1514        validPrimitive = validUnit(value, FNumber, m_strict);
1515        break;
1516    case CSSPropertyWebkitBoxFlexGroup:
1517    case CSSPropertyWebkitBoxOrdinalGroup:
1518        validPrimitive = validUnit(value, FInteger | FNonNeg, true);
1519        break;
1520    case CSSPropertyBoxSizing:
1521        validPrimitive = id == CSSValueBorderBox || id == CSSValueContentBox;
1522        break;
1523    case CSSPropertyWebkitColorCorrection:
1524        validPrimitive = id == CSSValueSrgb || id == CSSValueDefault;
1525        break;
1526    case CSSPropertyWebkitMarquee: {
1527        const int properties[5] = { CSSPropertyWebkitMarqueeDirection, CSSPropertyWebkitMarqueeIncrement,
1528                                    CSSPropertyWebkitMarqueeRepetition,
1529                                    CSSPropertyWebkitMarqueeStyle, CSSPropertyWebkitMarqueeSpeed };
1530        return parseShorthand(propId, properties, 5, important);
1531    }
1532    case CSSPropertyWebkitMarqueeDirection:
1533        if (id == CSSValueForwards || id == CSSValueBackwards || id == CSSValueAhead ||
1534            id == CSSValueReverse || id == CSSValueLeft || id == CSSValueRight || id == CSSValueDown ||
1535            id == CSSValueUp || id == CSSValueAuto)
1536            validPrimitive = true;
1537        break;
1538    case CSSPropertyWebkitMarqueeIncrement:
1539        if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
1540            validPrimitive = true;
1541        else
1542            validPrimitive = validUnit(value, FLength | FPercent, m_strict);
1543        break;
1544    case CSSPropertyWebkitMarqueeStyle:
1545        if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate)
1546            validPrimitive = true;
1547        break;
1548    case CSSPropertyWebkitMarqueeRepetition:
1549        if (id == CSSValueInfinite)
1550            validPrimitive = true;
1551        else
1552            validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict);
1553        break;
1554    case CSSPropertyWebkitMarqueeSpeed:
1555        if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
1556            validPrimitive = true;
1557        else
1558            validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict);
1559        break;
1560#if ENABLE(WCSS)
1561    case CSSPropertyWapMarqueeDir:
1562        if (id == CSSValueLtr || id == CSSValueRtl)
1563            validPrimitive = true;
1564        break;
1565    case CSSPropertyWapMarqueeStyle:
1566        if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate)
1567            validPrimitive = true;
1568        break;
1569    case CSSPropertyWapMarqueeLoop:
1570        if (id == CSSValueInfinite)
1571            validPrimitive = true;
1572        else
1573            validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict);
1574        break;
1575    case CSSPropertyWapMarqueeSpeed:
1576        if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
1577            validPrimitive = true;
1578        else
1579            validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict);
1580        break;
1581#endif
1582    case CSSPropertyWebkitUserDrag: // auto | none | element
1583        if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueElement)
1584            validPrimitive = true;
1585        break;
1586    case CSSPropertyWebkitUserModify: // read-only | read-write
1587        if (id == CSSValueReadOnly || id == CSSValueReadWrite || id == CSSValueReadWritePlaintextOnly)
1588            validPrimitive = true;
1589        break;
1590    case CSSPropertyWebkitUserSelect: // auto | none | text
1591        if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueText)
1592            validPrimitive = true;
1593        break;
1594    case CSSPropertyTextOverflow: // clip | ellipsis
1595        if (id == CSSValueClip || id == CSSValueEllipsis)
1596            validPrimitive = true;
1597        break;
1598    case CSSPropertyWebkitTransform:
1599        if (id == CSSValueNone)
1600            validPrimitive = true;
1601        else {
1602            PassRefPtr<CSSValue> val = parseTransform();
1603            if (val) {
1604                addProperty(propId, val, important);
1605                return true;
1606            }
1607            return false;
1608        }
1609        break;
1610    case CSSPropertyWebkitTransformOrigin:
1611    case CSSPropertyWebkitTransformOriginX:
1612    case CSSPropertyWebkitTransformOriginY:
1613    case CSSPropertyWebkitTransformOriginZ: {
1614        RefPtr<CSSValue> val1;
1615        RefPtr<CSSValue> val2;
1616        RefPtr<CSSValue> val3;
1617        int propId1, propId2, propId3;
1618        if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
1619            addProperty(propId1, val1.release(), important);
1620            if (val2)
1621                addProperty(propId2, val2.release(), important);
1622            if (val3)
1623                addProperty(propId3, val3.release(), important);
1624            return true;
1625        }
1626        return false;
1627    }
1628    case CSSPropertyWebkitTransformStyle:
1629        if (value->id == CSSValueFlat || value->id == CSSValuePreserve3d)
1630            validPrimitive = true;
1631        break;
1632    case CSSPropertyWebkitBackfaceVisibility:
1633        if (value->id == CSSValueVisible || value->id == CSSValueHidden)
1634            validPrimitive = true;
1635        break;
1636    case CSSPropertyWebkitPerspective:
1637        if (id == CSSValueNone)
1638            validPrimitive = true;
1639        else {
1640            // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
1641            if (validUnit(value, FNumber | FLength | FNonNeg, m_strict)) {
1642                RefPtr<CSSValue> val = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1643                if (val) {
1644                    addProperty(propId, val.release(), important);
1645                    return true;
1646                }
1647                return false;
1648            }
1649        }
1650        break;
1651    case CSSPropertyWebkitPerspectiveOrigin:
1652    case CSSPropertyWebkitPerspectiveOriginX:
1653    case CSSPropertyWebkitPerspectiveOriginY: {
1654        RefPtr<CSSValue> val1;
1655        RefPtr<CSSValue> val2;
1656        int propId1, propId2;
1657        if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
1658            addProperty(propId1, val1.release(), important);
1659            if (val2)
1660                addProperty(propId2, val2.release(), important);
1661            return true;
1662        }
1663        return false;
1664    }
1665    case CSSPropertyWebkitAnimationDelay:
1666    case CSSPropertyWebkitAnimationDirection:
1667    case CSSPropertyWebkitAnimationDuration:
1668    case CSSPropertyWebkitAnimationFillMode:
1669    case CSSPropertyWebkitAnimationName:
1670    case CSSPropertyWebkitAnimationPlayState:
1671    case CSSPropertyWebkitAnimationIterationCount:
1672    case CSSPropertyWebkitAnimationTimingFunction:
1673    case CSSPropertyWebkitTransitionDelay:
1674    case CSSPropertyWebkitTransitionDuration:
1675    case CSSPropertyWebkitTransitionTimingFunction:
1676    case CSSPropertyWebkitTransitionProperty: {
1677        RefPtr<CSSValue> val;
1678        if (parseAnimationProperty(propId, val)) {
1679            addProperty(propId, val.release(), important);
1680            return true;
1681        }
1682        return false;
1683    }
1684    case CSSPropertyWebkitMarginCollapse: {
1685        const int properties[2] = { CSSPropertyWebkitMarginBeforeCollapse,
1686            CSSPropertyWebkitMarginAfterCollapse };
1687        if (num == 1) {
1688            ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
1689            if (!parseValue(properties[0], important))
1690                return false;
1691            CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value();
1692            addProperty(properties[1], value, important);
1693            return true;
1694        }
1695        else if (num == 2) {
1696            ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
1697            if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
1698                return false;
1699            return true;
1700        }
1701        return false;
1702    }
1703    case CSSPropertyWebkitMarginBeforeCollapse:
1704    case CSSPropertyWebkitMarginAfterCollapse:
1705    case CSSPropertyWebkitMarginTopCollapse:
1706    case CSSPropertyWebkitMarginBottomCollapse:
1707        if (id == CSSValueCollapse || id == CSSValueSeparate || id == CSSValueDiscard)
1708            validPrimitive = true;
1709        break;
1710    case CSSPropertyTextLineThroughMode:
1711    case CSSPropertyTextOverlineMode:
1712    case CSSPropertyTextUnderlineMode:
1713        if (id == CSSValueContinuous || id == CSSValueSkipWhiteSpace)
1714            validPrimitive = true;
1715        break;
1716    case CSSPropertyTextLineThroughStyle:
1717    case CSSPropertyTextOverlineStyle:
1718    case CSSPropertyTextUnderlineStyle:
1719        if (id == CSSValueNone || id == CSSValueSolid || id == CSSValueDouble ||
1720            id == CSSValueDashed || id == CSSValueDotDash || id == CSSValueDotDotDash ||
1721            id == CSSValueWave)
1722            validPrimitive = true;
1723        break;
1724    case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
1725        if (id == CSSValueAuto || id == CSSValueOptimizespeed || id == CSSValueOptimizelegibility
1726            || id == CSSValueGeometricprecision)
1727            validPrimitive = true;
1728        break;
1729    case CSSPropertyTextLineThroughWidth:
1730    case CSSPropertyTextOverlineWidth:
1731    case CSSPropertyTextUnderlineWidth:
1732        if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
1733            id == CSSValueMedium || id == CSSValueThick)
1734            validPrimitive = true;
1735        else
1736            validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent, m_strict);
1737        break;
1738    case CSSPropertyResize: // none | both | horizontal | vertical | auto
1739        if (id == CSSValueNone || id == CSSValueBoth || id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
1740            validPrimitive = true;
1741        break;
1742    case CSSPropertyWebkitColumnCount:
1743        if (id == CSSValueAuto)
1744            validPrimitive = true;
1745        else
1746            validPrimitive = !id && validUnit(value, FInteger | FNonNeg, false);
1747        break;
1748    case CSSPropertyWebkitColumnGap:         // normal | <length>
1749        if (id == CSSValueNormal)
1750            validPrimitive = true;
1751        else
1752            validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
1753        break;
1754    case CSSPropertyWebkitColumnSpan:        // all | 1
1755        if (id == CSSValueAll)
1756            validPrimitive = true;
1757        else
1758            validPrimitive = validUnit(value, FNumber | FNonNeg, m_strict) && value->fValue == 1;
1759        break;
1760    case CSSPropertyWebkitColumnWidth:         // auto | <length>
1761        if (id == CSSValueAuto)
1762            validPrimitive = true;
1763        else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property.
1764            validPrimitive = validUnit(value, FLength, true);
1765        break;
1766    case CSSPropertyPointerEvents:
1767        // none | visiblePainted | visibleFill | visibleStroke | visible |
1768        // painted | fill | stroke | auto | all | inherit
1769        if (id == CSSValueVisible || id == CSSValueNone || id == CSSValueAll || id == CSSValueAuto ||
1770            (id >= CSSValueVisiblepainted && id <= CSSValueStroke))
1771            validPrimitive = true;
1772        break;
1773
1774    // End of CSS3 properties
1775
1776    // Apple specific properties.  These will never be standardized and are purely to
1777    // support custom WebKit-based Apple applications.
1778    case CSSPropertyWebkitLineClamp:
1779        // When specifying number of lines, don't allow 0 as a valid value
1780        // When specifying either type of unit, require non-negative integers
1781        validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, false));
1782        break;
1783    case CSSPropertyWebkitTextSizeAdjust:
1784        if (id == CSSValueAuto || id == CSSValueNone)
1785            validPrimitive = true;
1786        break;
1787    case CSSPropertyWebkitRtlOrdering:
1788        if (id == CSSValueLogical || id == CSSValueVisual)
1789            validPrimitive = true;
1790        break;
1791
1792    case CSSPropertyWebkitFontSizeDelta:           // <length>
1793        validPrimitive = validUnit(value, FLength, m_strict);
1794        break;
1795
1796    case CSSPropertyWebkitNbspMode:     // normal | space
1797        if (id == CSSValueNormal || id == CSSValueSpace)
1798            validPrimitive = true;
1799        break;
1800
1801    case CSSPropertyWebkitLineBreak:   // normal | after-white-space
1802        if (id == CSSValueNormal || id == CSSValueAfterWhiteSpace)
1803            validPrimitive = true;
1804        break;
1805
1806    case CSSPropertyWebkitMatchNearestMailBlockquoteColor:   // normal | match
1807        if (id == CSSValueNormal || id == CSSValueMatch)
1808            validPrimitive = true;
1809        break;
1810
1811    case CSSPropertyWebkitHighlight:
1812        if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
1813            validPrimitive = true;
1814        break;
1815
1816    case CSSPropertyWebkitHyphens:
1817        if (id == CSSValueNone || id == CSSValueManual || id == CSSValueAuto)
1818            validPrimitive = true;
1819        break;
1820
1821    case CSSPropertyWebkitHyphenateCharacter:
1822        if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
1823            validPrimitive = true;
1824        break;
1825
1826    case CSSPropertyWebkitHyphenateLimitBefore:
1827    case CSSPropertyWebkitHyphenateLimitAfter:
1828        if (id == CSSValueAuto || validUnit(value, FInteger | FNonNeg, true))
1829            validPrimitive = true;
1830        break;
1831
1832    case CSSPropertyWebkitLocale:
1833        if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
1834            validPrimitive = true;
1835        break;
1836
1837    case CSSPropertyWebkitBorderFit:
1838        if (id == CSSValueBorder || id == CSSValueLines)
1839            validPrimitive = true;
1840        break;
1841
1842    case CSSPropertyWebkitTextSecurity:
1843        // disc | circle | square | none | inherit
1844        if (id == CSSValueDisc || id == CSSValueCircle || id == CSSValueSquare|| id == CSSValueNone)
1845            validPrimitive = true;
1846        break;
1847
1848    case CSSPropertyWebkitFontSmoothing:
1849        if (id == CSSValueAuto || id == CSSValueNone
1850            || id == CSSValueAntialiased || id == CSSValueSubpixelAntialiased)
1851            validPrimitive = true;
1852        break;
1853
1854#if ENABLE(DASHBOARD_SUPPORT)
1855    case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region>
1856        if (value->unit == CSSParserValue::Function || id == CSSValueNone)
1857            return parseDashboardRegions(propId, important);
1858        break;
1859#endif
1860    // End Apple-specific properties
1861
1862        /* shorthand properties */
1863    case CSSPropertyBackground: {
1864        // Position must come before color in this array because a plain old "0" is a legal color
1865        // in quirks mode but it's usually the X coordinate of a position.
1866        // FIXME: Add CSSPropertyBackgroundSize to the shorthand.
1867        const int properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
1868                                   CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
1869                                   CSSPropertyBackgroundClip, CSSPropertyBackgroundColor };
1870        return parseFillShorthand(propId, properties, 7, important);
1871    }
1872    case CSSPropertyWebkitMask: {
1873        const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
1874                                   CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition,
1875                                   CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip };
1876        return parseFillShorthand(propId, properties, 6, important);
1877    }
1878    case CSSPropertyBorder:
1879        // [ 'border-width' || 'border-style' || <color> ] | inherit
1880    {
1881        const int properties[3] = { CSSPropertyBorderWidth, CSSPropertyBorderStyle,
1882                                    CSSPropertyBorderColor };
1883        return parseShorthand(propId, properties, 3, important);
1884    }
1885    case CSSPropertyBorderTop:
1886        // [ 'border-top-width' || 'border-style' || <color> ] | inherit
1887    {
1888        const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle,
1889                                    CSSPropertyBorderTopColor};
1890        return parseShorthand(propId, properties, 3, important);
1891    }
1892    case CSSPropertyBorderRight:
1893        // [ 'border-right-width' || 'border-style' || <color> ] | inherit
1894    {
1895        const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle,
1896                                    CSSPropertyBorderRightColor };
1897        return parseShorthand(propId, properties, 3, important);
1898    }
1899    case CSSPropertyBorderBottom:
1900        // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
1901    {
1902        const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle,
1903                                    CSSPropertyBorderBottomColor };
1904        return parseShorthand(propId, properties, 3, important);
1905    }
1906    case CSSPropertyBorderLeft:
1907        // [ 'border-left-width' || 'border-style' || <color> ] | inherit
1908    {
1909        const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle,
1910                                    CSSPropertyBorderLeftColor };
1911        return parseShorthand(propId, properties, 3, important);
1912    }
1913    case CSSPropertyWebkitBorderStart:
1914    {
1915        const int properties[3] = { CSSPropertyWebkitBorderStartWidth, CSSPropertyWebkitBorderStartStyle,
1916            CSSPropertyWebkitBorderStartColor };
1917        return parseShorthand(propId, properties, 3, important);
1918    }
1919    case CSSPropertyWebkitBorderEnd:
1920    {
1921        const int properties[3] = { CSSPropertyWebkitBorderEndWidth, CSSPropertyWebkitBorderEndStyle,
1922            CSSPropertyWebkitBorderEndColor };
1923        return parseShorthand(propId, properties, 3, important);
1924    }
1925    case CSSPropertyWebkitBorderBefore:
1926    {
1927        const int properties[3] = { CSSPropertyWebkitBorderBeforeWidth, CSSPropertyWebkitBorderBeforeStyle,
1928            CSSPropertyWebkitBorderBeforeColor };
1929        return parseShorthand(propId, properties, 3, important);
1930    }
1931    case CSSPropertyWebkitBorderAfter:
1932    {
1933        const int properties[3] = { CSSPropertyWebkitBorderAfterWidth, CSSPropertyWebkitBorderAfterStyle,
1934            CSSPropertyWebkitBorderAfterColor };
1935        return parseShorthand(propId, properties, 3, important);
1936    }
1937    case CSSPropertyOutline:
1938        // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
1939    {
1940        const int properties[3] = { CSSPropertyOutlineWidth, CSSPropertyOutlineStyle,
1941                                    CSSPropertyOutlineColor };
1942        return parseShorthand(propId, properties, 3, important);
1943    }
1944    case CSSPropertyBorderColor:
1945        // <color>{1,4} | inherit
1946    {
1947        const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor,
1948                                    CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor };
1949        return parse4Values(propId, properties, important);
1950    }
1951    case CSSPropertyBorderWidth:
1952        // <border-width>{1,4} | inherit
1953    {
1954        const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth,
1955                                    CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth };
1956        return parse4Values(propId, properties, important);
1957    }
1958    case CSSPropertyBorderStyle:
1959        // <border-style>{1,4} | inherit
1960    {
1961        const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle,
1962                                    CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle };
1963        return parse4Values(propId, properties, important);
1964    }
1965    case CSSPropertyMargin:
1966        // <margin-width>{1,4} | inherit
1967    {
1968        const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight,
1969                                    CSSPropertyMarginBottom, CSSPropertyMarginLeft };
1970        return parse4Values(propId, properties, important);
1971    }
1972    case CSSPropertyPadding:
1973        // <padding-width>{1,4} | inherit
1974    {
1975        const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight,
1976                                    CSSPropertyPaddingBottom, CSSPropertyPaddingLeft };
1977        return parse4Values(propId, properties, important);
1978    }
1979    case CSSPropertyFont:
1980        // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
1981        // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
1982        if (id >= CSSValueCaption && id <= CSSValueStatusBar)
1983            validPrimitive = true;
1984        else
1985            return parseFont(important);
1986        break;
1987    case CSSPropertyListStyle:
1988    {
1989        const int properties[3] = { CSSPropertyListStyleType, CSSPropertyListStylePosition,
1990                                    CSSPropertyListStyleImage };
1991        return parseShorthand(propId, properties, 3, important);
1992    }
1993    case CSSPropertyWebkitColumns: {
1994        const int properties[2] = { CSSPropertyWebkitColumnWidth, CSSPropertyWebkitColumnCount };
1995        return parseShorthand(propId, properties, 2, important);
1996    }
1997    case CSSPropertyWebkitColumnRule: {
1998        const int properties[3] = { CSSPropertyWebkitColumnRuleWidth, CSSPropertyWebkitColumnRuleStyle,
1999                                    CSSPropertyWebkitColumnRuleColor };
2000        return parseShorthand(propId, properties, 3, important);
2001    }
2002    case CSSPropertyWebkitTextStroke: {
2003        const int properties[2] = { CSSPropertyWebkitTextStrokeWidth, CSSPropertyWebkitTextStrokeColor };
2004        return parseShorthand(propId, properties, 2, important);
2005    }
2006    case CSSPropertyWebkitAnimation:
2007        return parseAnimationShorthand(important);
2008    case CSSPropertyWebkitTransition:
2009        return parseTransitionShorthand(important);
2010    case CSSPropertyInvalid:
2011        return false;
2012    case CSSPropertyPage:
2013        return parsePage(propId, important);
2014    case CSSPropertyFontStretch:
2015    case CSSPropertyTextLineThrough:
2016    case CSSPropertyTextOverline:
2017    case CSSPropertyTextUnderline:
2018        return false;
2019
2020#if ENABLE(WCSS)
2021    case CSSPropertyWapInputFormat:
2022        validPrimitive = true;
2023        break;
2024    case CSSPropertyWapInputRequired:
2025        parsedValue = parseWCSSInputProperty();
2026        break;
2027#endif
2028
2029    // CSS Text Layout Module Level 3: Vertical writing support
2030    case CSSPropertyWebkitWritingMode:
2031        if (id >= CSSValueHorizontalTb && id <= CSSValueHorizontalBt)
2032            validPrimitive = true;
2033        break;
2034
2035    case CSSPropertyWebkitTextCombine:
2036        if (id == CSSValueNone || id == CSSValueHorizontal)
2037            validPrimitive = true;
2038        break;
2039
2040    case CSSPropertyWebkitTextEmphasis: {
2041        const int properties[] = { CSSPropertyWebkitTextEmphasisStyle, CSSPropertyWebkitTextEmphasisColor };
2042        return parseShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
2043    }
2044
2045    case CSSPropertyWebkitTextEmphasisPosition:
2046        if (id == CSSValueOver || id == CSSValueUnder)
2047            validPrimitive = true;
2048        break;
2049
2050    case CSSPropertyWebkitTextEmphasisStyle:
2051        return parseTextEmphasisStyle(important);
2052
2053    case CSSPropertyWebkitTextOrientation:
2054        // FIXME: For now just support upright and vertical-right.
2055        if (id == CSSValueVerticalRight || id == CSSValueUpright)
2056            validPrimitive = true;
2057        break;
2058
2059    case CSSPropertyWebkitLineBoxContain:
2060        if (id == CSSValueNone)
2061            validPrimitive = true;
2062        else
2063            return parseLineBoxContain(important);
2064        break;
2065
2066#ifdef ANDROID_CSS_RING
2067    case CSSPropertyWebkitRing:
2068    {
2069        const int properties[9] = { CSSPropertyWebkitRingFillColor,
2070                                    CSSPropertyWebkitRingInnerWidth,
2071                                    CSSPropertyWebkitRingOuterWidth,
2072                                    CSSPropertyWebkitRingOutset,
2073                                    CSSPropertyWebkitRingPressedInnerColor,
2074                                    CSSPropertyWebkitRingPressedOuterColor,
2075                                    CSSPropertyWebkitRingRadius,
2076                                    CSSPropertyWebkitRingSelectedInnerColor,
2077                                    CSSPropertyWebkitRingSelectedOuterColor };
2078        return parseShorthand(propId, properties, 9, important);
2079    }
2080    case CSSPropertyWebkitRingFillColor:
2081    case CSSPropertyWebkitRingPressedInnerColor:
2082    case CSSPropertyWebkitRingPressedOuterColor:
2083    case CSSPropertyWebkitRingSelectedInnerColor:
2084    case CSSPropertyWebkitRingSelectedOuterColor:
2085        parsedValue = parseColor();
2086        if (parsedValue)
2087            m_valueList->next();
2088        break;
2089    case CSSPropertyWebkitRingInnerWidth:
2090    case CSSPropertyWebkitRingOuterWidth:
2091    case CSSPropertyWebkitRingOutset:
2092    case CSSPropertyWebkitRingRadius:
2093        validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
2094        break;
2095#endif
2096#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
2097    case CSSPropertyWebkitTapHighlightColor:
2098        parsedValue = parseColor();
2099        if (parsedValue)
2100            m_valueList->next();
2101        break;
2102#endif
2103
2104#if ENABLE(SVG)
2105    default:
2106        return parseSVGValue(propId, important);
2107#endif
2108    }
2109
2110    if (validPrimitive) {
2111        if (id != 0)
2112            parsedValue = primitiveValueCache()->createIdentifierValue(id);
2113        else if (value->unit == CSSPrimitiveValue::CSS_STRING)
2114            parsedValue = primitiveValueCache()->createValue(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
2115        else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
2116            parsedValue = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
2117        else if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS)
2118            parsedValue = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
2119        else if (value->unit >= CSSParserValue::Q_EMS)
2120            parsedValue = CSSQuirkPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_EMS);
2121        m_valueList->next();
2122    }
2123    if (parsedValue) {
2124        if (!m_valueList->current() || inShorthand()) {
2125            addProperty(propId, parsedValue.release(), important);
2126            return true;
2127        }
2128    }
2129    return false;
2130}
2131
2132#if ENABLE(WCSS)
2133PassRefPtr<CSSValue> CSSParser::parseWCSSInputProperty()
2134{
2135    RefPtr<CSSValue> parsedValue = 0;
2136    CSSParserValue* value = m_valueList->current();
2137    String inputProperty;
2138    if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT)
2139        inputProperty = String(value->string);
2140
2141    if (!inputProperty.isEmpty())
2142       parsedValue = primitiveValueCache()->createValue(inputProperty, CSSPrimitiveValue::CSS_STRING);
2143
2144    while (m_valueList->next()) {
2145    // pass all other values, if any. If we don't do this,
2146    // the parser will think that it's not done and won't process this property
2147    }
2148
2149    return parsedValue;
2150}
2151#endif
2152
2153void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
2154{
2155    if (lval) {
2156        if (lval->isValueList())
2157            static_cast<CSSValueList*>(lval.get())->append(rval);
2158        else {
2159            PassRefPtr<CSSValue> oldlVal(lval.release());
2160            PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
2161            list->append(oldlVal);
2162            list->append(rval);
2163            lval = list;
2164        }
2165    }
2166    else
2167        lval = rval;
2168}
2169
2170static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue, CSSPrimitiveValueCache* primitiveValueCache)
2171{
2172    if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
2173        || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
2174        cssValue = primitiveValueCache->createIdentifierValue(parserValue->id);
2175        return true;
2176    }
2177    return false;
2178}
2179
2180const int cMaxFillProperties = 9;
2181
2182bool CSSParser::parseFillShorthand(int propId, const int* properties, int numProperties, bool important)
2183{
2184    ASSERT(numProperties <= cMaxFillProperties);
2185    if (numProperties > cMaxFillProperties)
2186        return false;
2187
2188    ShorthandScope scope(this, propId);
2189
2190    bool parsedProperty[cMaxFillProperties] = { false };
2191    RefPtr<CSSValue> values[cMaxFillProperties];
2192    RefPtr<CSSValue> clipValue;
2193    RefPtr<CSSValue> positionYValue;
2194    RefPtr<CSSValue> repeatYValue;
2195    bool foundClip = false;
2196    int i;
2197
2198    while (m_valueList->current()) {
2199        CSSParserValue* val = m_valueList->current();
2200        if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
2201            // We hit the end.  Fill in all remaining values with the initial value.
2202            m_valueList->next();
2203            for (i = 0; i < numProperties; ++i) {
2204                if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
2205                    // Color is not allowed except as the last item in a list for backgrounds.
2206                    // Reject the entire property.
2207                    return false;
2208
2209                if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
2210                    addFillValue(values[i], CSSInitialValue::createImplicit());
2211                    if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2212                        addFillValue(positionYValue, CSSInitialValue::createImplicit());
2213                    if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2214                        addFillValue(repeatYValue, CSSInitialValue::createImplicit());
2215                    if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
2216                        // If background-origin wasn't present, then reset background-clip also.
2217                        addFillValue(clipValue, CSSInitialValue::createImplicit());
2218                    }
2219                }
2220                parsedProperty[i] = false;
2221            }
2222            if (!m_valueList->current())
2223                break;
2224        }
2225
2226        bool found = false;
2227        for (i = 0; !found && i < numProperties; ++i) {
2228            if (!parsedProperty[i]) {
2229                RefPtr<CSSValue> val1;
2230                RefPtr<CSSValue> val2;
2231                int propId1, propId2;
2232                CSSParserValue* parserValue = m_valueList->current();
2233                if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
2234                    parsedProperty[i] = found = true;
2235                    addFillValue(values[i], val1.release());
2236                    if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2237                        addFillValue(positionYValue, val2.release());
2238                    if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2239                        addFillValue(repeatYValue, val2.release());
2240                    if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
2241                        // Reparse the value as a clip, and see if we succeed.
2242                        if (parseBackgroundClip(parserValue, val1, primitiveValueCache()))
2243                            addFillValue(clipValue, val1.release()); // The property parsed successfully.
2244                        else
2245                            addFillValue(clipValue, CSSInitialValue::createImplicit()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
2246                    }
2247                    if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
2248                        // Update clipValue
2249                        addFillValue(clipValue, val1.release());
2250                        foundClip = true;
2251                    }
2252                }
2253            }
2254        }
2255
2256        // if we didn't find at least one match, this is an
2257        // invalid shorthand and we have to ignore it
2258        if (!found)
2259            return false;
2260    }
2261
2262    // Fill in any remaining properties with the initial value.
2263    for (i = 0; i < numProperties; ++i) {
2264        if (!parsedProperty[i]) {
2265            addFillValue(values[i], CSSInitialValue::createImplicit());
2266            if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2267                addFillValue(positionYValue, CSSInitialValue::createImplicit());
2268            if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2269                addFillValue(repeatYValue, CSSInitialValue::createImplicit());
2270            if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
2271                // If background-origin wasn't present, then reset background-clip also.
2272                addFillValue(clipValue, CSSInitialValue::createImplicit());
2273            }
2274        }
2275    }
2276
2277    // Now add all of the properties we found.
2278    for (i = 0; i < numProperties; i++) {
2279        if (properties[i] == CSSPropertyBackgroundPosition) {
2280            addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
2281            // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
2282            addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
2283        } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
2284            addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
2285            // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
2286            addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
2287        } else if (properties[i] == CSSPropertyBackgroundRepeat) {
2288            addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
2289            // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
2290            addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
2291        } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
2292            addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
2293            // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
2294            addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
2295        } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
2296            // Value is already set while updating origin
2297            continue;
2298        else
2299            addProperty(properties[i], values[i].release(), important);
2300
2301        // Add in clip values when we hit the corresponding origin property.
2302        if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
2303            addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
2304        else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
2305            addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
2306    }
2307
2308    return true;
2309}
2310
2311void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
2312{
2313    if (lval) {
2314        if (lval->isValueList())
2315            static_cast<CSSValueList*>(lval.get())->append(rval);
2316        else {
2317            PassRefPtr<CSSValue> oldVal(lval.release());
2318            PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
2319            list->append(oldVal);
2320            list->append(rval);
2321            lval = list;
2322        }
2323    }
2324    else
2325        lval = rval;
2326}
2327
2328bool CSSParser::parseAnimationShorthand(bool important)
2329{
2330    const int properties[] = {  CSSPropertyWebkitAnimationName,
2331                                CSSPropertyWebkitAnimationDuration,
2332                                CSSPropertyWebkitAnimationTimingFunction,
2333                                CSSPropertyWebkitAnimationDelay,
2334                                CSSPropertyWebkitAnimationIterationCount,
2335                                CSSPropertyWebkitAnimationDirection,
2336                                CSSPropertyWebkitAnimationFillMode };
2337    const int numProperties = WTF_ARRAY_LENGTH(properties);
2338
2339    ShorthandScope scope(this, CSSPropertyWebkitAnimation);
2340
2341    bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
2342    RefPtr<CSSValue> values[numProperties];
2343
2344    int i;
2345    while (m_valueList->current()) {
2346        CSSParserValue* val = m_valueList->current();
2347        if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
2348            // We hit the end.  Fill in all remaining values with the initial value.
2349            m_valueList->next();
2350            for (i = 0; i < numProperties; ++i) {
2351                if (!parsedProperty[i])
2352                    addAnimationValue(values[i], CSSInitialValue::createImplicit());
2353                parsedProperty[i] = false;
2354            }
2355            if (!m_valueList->current())
2356                break;
2357        }
2358
2359        bool found = false;
2360        for (i = 0; !found && i < numProperties; ++i) {
2361            if (!parsedProperty[i]) {
2362                RefPtr<CSSValue> val;
2363                if (parseAnimationProperty(properties[i], val)) {
2364                    parsedProperty[i] = found = true;
2365                    addAnimationValue(values[i], val.release());
2366                }
2367            }
2368        }
2369
2370        // if we didn't find at least one match, this is an
2371        // invalid shorthand and we have to ignore it
2372        if (!found)
2373            return false;
2374    }
2375
2376    // Fill in any remaining properties with the initial value.
2377    for (i = 0; i < numProperties; ++i) {
2378        if (!parsedProperty[i])
2379            addAnimationValue(values[i], CSSInitialValue::createImplicit());
2380    }
2381
2382    // Now add all of the properties we found.
2383    for (i = 0; i < numProperties; i++)
2384        addProperty(properties[i], values[i].release(), important);
2385
2386    return true;
2387}
2388
2389bool CSSParser::parseTransitionShorthand(bool important)
2390{
2391    const int properties[] = { CSSPropertyWebkitTransitionProperty,
2392                               CSSPropertyWebkitTransitionDuration,
2393                               CSSPropertyWebkitTransitionTimingFunction,
2394                               CSSPropertyWebkitTransitionDelay };
2395    const int numProperties = WTF_ARRAY_LENGTH(properties);
2396
2397    ShorthandScope scope(this, CSSPropertyWebkitTransition);
2398
2399    bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
2400    RefPtr<CSSValue> values[numProperties];
2401
2402    int i;
2403    while (m_valueList->current()) {
2404        CSSParserValue* val = m_valueList->current();
2405        if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
2406            // We hit the end.  Fill in all remaining values with the initial value.
2407            m_valueList->next();
2408            for (i = 0; i < numProperties; ++i) {
2409                if (!parsedProperty[i])
2410                    addAnimationValue(values[i], CSSInitialValue::createImplicit());
2411                parsedProperty[i] = false;
2412            }
2413            if (!m_valueList->current())
2414                break;
2415        }
2416
2417        bool found = false;
2418        for (i = 0; !found && i < numProperties; ++i) {
2419            if (!parsedProperty[i]) {
2420                RefPtr<CSSValue> val;
2421                if (parseAnimationProperty(properties[i], val)) {
2422                    parsedProperty[i] = found = true;
2423                    addAnimationValue(values[i], val.release());
2424                }
2425            }
2426        }
2427
2428        // if we didn't find at least one match, this is an
2429        // invalid shorthand and we have to ignore it
2430        if (!found)
2431            return false;
2432    }
2433
2434    // Fill in any remaining properties with the initial value.
2435    for (i = 0; i < numProperties; ++i) {
2436        if (!parsedProperty[i])
2437            addAnimationValue(values[i], CSSInitialValue::createImplicit());
2438    }
2439
2440    // Now add all of the properties we found.
2441    for (i = 0; i < numProperties; i++)
2442        addProperty(properties[i], values[i].release(), important);
2443
2444    return true;
2445}
2446
2447bool CSSParser::parseShorthand(int propId, const int *properties, int numProperties, bool important)
2448{
2449    // We try to match as many properties as possible
2450    // We set up an array of booleans to mark which property has been found,
2451    // and we try to search for properties until it makes no longer any sense.
2452    ShorthandScope scope(this, propId);
2453
2454    bool found = false;
2455    bool fnd[6]; // Trust me ;)
2456    for (int i = 0; i < numProperties; i++)
2457        fnd[i] = false;
2458
2459    while (m_valueList->current()) {
2460        found = false;
2461        for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
2462            if (!fnd[propIndex]) {
2463                if (parseValue(properties[propIndex], important))
2464                    fnd[propIndex] = found = true;
2465            }
2466        }
2467
2468        // if we didn't find at least one match, this is an
2469        // invalid shorthand and we have to ignore it
2470        if (!found)
2471            return false;
2472    }
2473
2474    // Fill in any remaining properties with the initial value.
2475    m_implicitShorthand = true;
2476    for (int i = 0; i < numProperties; ++i) {
2477        if (!fnd[i])
2478            addProperty(properties[i], CSSInitialValue::createImplicit(), important);
2479    }
2480    m_implicitShorthand = false;
2481
2482    return true;
2483}
2484
2485bool CSSParser::parse4Values(int propId, const int *properties,  bool important)
2486{
2487    /* From the CSS 2 specs, 8.3
2488     * If there is only one value, it applies to all sides. If there are two values, the top and
2489     * bottom margins are set to the first value and the right and left margins are set to the second.
2490     * If there are three values, the top is set to the first value, the left and right are set to the
2491     * second, and the bottom is set to the third. If there are four values, they apply to the top,
2492     * right, bottom, and left, respectively.
2493     */
2494
2495    int num = inShorthand() ? 1 : m_valueList->size();
2496
2497    ShorthandScope scope(this, propId);
2498
2499    // the order is top, right, bottom, left
2500    switch (num) {
2501        case 1: {
2502            if (!parseValue(properties[0], important))
2503                return false;
2504            CSSValue *value = m_parsedProperties[m_numParsedProperties-1]->value();
2505            m_implicitShorthand = true;
2506            addProperty(properties[1], value, important);
2507            addProperty(properties[2], value, important);
2508            addProperty(properties[3], value, important);
2509            m_implicitShorthand = false;
2510            break;
2511        }
2512        case 2: {
2513            if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
2514                return false;
2515            CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value();
2516            m_implicitShorthand = true;
2517            addProperty(properties[2], value, important);
2518            value = m_parsedProperties[m_numParsedProperties-2]->value();
2519            addProperty(properties[3], value, important);
2520            m_implicitShorthand = false;
2521            break;
2522        }
2523        case 3: {
2524            if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
2525                return false;
2526            CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value();
2527            m_implicitShorthand = true;
2528            addProperty(properties[3], value, important);
2529            m_implicitShorthand = false;
2530            break;
2531        }
2532        case 4: {
2533            if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
2534                !parseValue(properties[2], important) || !parseValue(properties[3], important))
2535                return false;
2536            break;
2537        }
2538        default: {
2539            return false;
2540        }
2541    }
2542
2543    return true;
2544}
2545
2546// auto | <identifier>
2547bool CSSParser::parsePage(int propId, bool important)
2548{
2549    ASSERT(propId == CSSPropertyPage);
2550
2551    if (m_valueList->size() != 1)
2552        return false;
2553
2554    CSSParserValue* value = m_valueList->current();
2555    if (!value)
2556        return false;
2557
2558    if (value->id == CSSValueAuto) {
2559        addProperty(propId, primitiveValueCache()->createIdentifierValue(value->id), important);
2560        return true;
2561    } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
2562        addProperty(propId, primitiveValueCache()->createValue(value->string, CSSPrimitiveValue::CSS_STRING), important);
2563        return true;
2564    }
2565    return false;
2566}
2567
2568// <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
2569bool CSSParser::parseSize(int propId, bool important)
2570{
2571    ASSERT(propId == CSSPropertySize);
2572
2573    if (m_valueList->size() > 2)
2574        return false;
2575
2576    CSSParserValue* value = m_valueList->current();
2577    if (!value)
2578        return false;
2579
2580    RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
2581
2582    // First parameter.
2583    SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
2584    if (paramType == None)
2585        return false;
2586
2587    // Second parameter, if any.
2588    value = m_valueList->next();
2589    if (value) {
2590        paramType = parseSizeParameter(parsedValues.get(), value, paramType);
2591        if (paramType == None)
2592            return false;
2593    }
2594
2595    addProperty(propId, parsedValues.release(), important);
2596    return true;
2597}
2598
2599CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
2600{
2601    switch (value->id) {
2602    case CSSValueAuto:
2603        if (prevParamType == None) {
2604            parsedValues->append(primitiveValueCache()->createIdentifierValue(value->id));
2605            return Auto;
2606        }
2607        return None;
2608    case CSSValueLandscape:
2609    case CSSValuePortrait:
2610        if (prevParamType == None || prevParamType == PageSize) {
2611            parsedValues->append(primitiveValueCache()->createIdentifierValue(value->id));
2612            return Orientation;
2613        }
2614        return None;
2615    case CSSValueA3:
2616    case CSSValueA4:
2617    case CSSValueA5:
2618    case CSSValueB4:
2619    case CSSValueB5:
2620    case CSSValueLedger:
2621    case CSSValueLegal:
2622    case CSSValueLetter:
2623        if (prevParamType == None || prevParamType == Orientation) {
2624            // Normalize to Page Size then Orientation order by prepending.
2625            // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (CSSStyleSelector::applyPageSizeProperty).
2626            parsedValues->prepend(primitiveValueCache()->createIdentifierValue(value->id));
2627            return PageSize;
2628        }
2629        return None;
2630    case 0:
2631        if (validUnit(value, FLength | FNonNeg, m_strict) && (prevParamType == None || prevParamType == Length)) {
2632            parsedValues->append(primitiveValueCache()->createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
2633            return Length;
2634        }
2635        return None;
2636    default:
2637        return None;
2638    }
2639}
2640
2641// [ <string> <string> ]+ | inherit | none
2642// inherit and none are handled in parseValue.
2643bool CSSParser::parseQuotes(int propId, bool important)
2644{
2645    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
2646    while (CSSParserValue* val = m_valueList->current()) {
2647        RefPtr<CSSValue> parsedValue;
2648        if (val->unit == CSSPrimitiveValue::CSS_STRING)
2649            parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
2650        else
2651            break;
2652        values->append(parsedValue.release());
2653        m_valueList->next();
2654    }
2655    if (values->length()) {
2656        addProperty(propId, values.release(), important);
2657        m_valueList->next();
2658        return true;
2659    }
2660    return false;
2661}
2662
2663// [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
2664// in CSS 2.1 this got somewhat reduced:
2665// [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
2666bool CSSParser::parseContent(int propId, bool important)
2667{
2668    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
2669
2670    while (CSSParserValue* val = m_valueList->current()) {
2671        RefPtr<CSSValue> parsedValue;
2672        if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
2673            // url
2674            // FIXME: The completeURL call should be done when using the CSSImageValue,
2675            // not when creating it.
2676            parsedValue = CSSImageValue::create(m_styleSheet->completeURL(val->string));
2677        } else if (val->unit == CSSParserValue::Function) {
2678            // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
2679            CSSParserValueList* args = val->function->args.get();
2680            if (!args)
2681                return false;
2682            if (equalIgnoringCase(val->function->name, "attr(")) {
2683                parsedValue = parseAttr(args);
2684                if (!parsedValue)
2685                    return false;
2686            } else if (equalIgnoringCase(val->function->name, "counter(")) {
2687                parsedValue = parseCounterContent(args, false);
2688                if (!parsedValue)
2689                    return false;
2690            } else if (equalIgnoringCase(val->function->name, "counters(")) {
2691                parsedValue = parseCounterContent(args, true);
2692                if (!parsedValue)
2693                    return false;
2694            } else if (isGeneratedImageValue(val)) {
2695                if (!parseGeneratedImage(parsedValue))
2696                    return false;
2697            } else
2698                return false;
2699        } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
2700            // open-quote
2701            // close-quote
2702            // no-open-quote
2703            // no-close-quote
2704            // inherit
2705            // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
2706            // none
2707            // normal
2708            switch (val->id) {
2709            case CSSValueOpenQuote:
2710            case CSSValueCloseQuote:
2711            case CSSValueNoOpenQuote:
2712            case CSSValueNoCloseQuote:
2713            case CSSValueNone:
2714            case CSSValueNormal:
2715                parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
2716            }
2717        } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
2718            parsedValue = primitiveValueCache()->createValue(val->string, CSSPrimitiveValue::CSS_STRING);
2719        }
2720        if (!parsedValue)
2721            break;
2722        values->append(parsedValue.release());
2723        m_valueList->next();
2724    }
2725
2726    if (values->length()) {
2727        addProperty(propId, values.release(), important);
2728        m_valueList->next();
2729        return true;
2730    }
2731
2732    return false;
2733}
2734
2735PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args)
2736{
2737    if (args->size() != 1)
2738        return 0;
2739
2740    CSSParserValue* a = args->current();
2741
2742    if (a->unit != CSSPrimitiveValue::CSS_IDENT)
2743        return 0;
2744
2745    String attrName = a->string;
2746    // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
2747    // But HTML attribute names can't have those characters, and we should not
2748    // even parse them inside attr().
2749    if (attrName[0] == '-')
2750        return 0;
2751
2752    if (document() && document()->isHTMLDocument())
2753        attrName = attrName.lower();
2754
2755    return primitiveValueCache()->createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
2756}
2757
2758PassRefPtr<CSSValue> CSSParser::parseBackgroundColor()
2759{
2760    int id = m_valueList->current()->id;
2761    if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
2762        (id >= CSSValueGrey && id < CSSValueWebkitText && !m_strict))
2763       return primitiveValueCache()->createIdentifierValue(id);
2764    return parseColor();
2765}
2766
2767bool CSSParser::parseFillImage(RefPtr<CSSValue>& value)
2768{
2769    if (m_valueList->current()->id == CSSValueNone) {
2770        value = CSSImageValue::create();
2771        return true;
2772    }
2773    if (m_valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
2774        // FIXME: The completeURL call should be done when using the CSSImageValue,
2775        // not when creating it.
2776        if (m_styleSheet)
2777            value = CSSImageValue::create(m_styleSheet->completeURL(m_valueList->current()->string));
2778        return true;
2779    }
2780
2781    if (isGeneratedImageValue(m_valueList->current()))
2782        return parseGeneratedImage(value);
2783
2784    return false;
2785}
2786
2787PassRefPtr<CSSValue> CSSParser::parseFillPositionX(CSSParserValueList* valueList)
2788{
2789    int id = valueList->current()->id;
2790    if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
2791        int percent = 0;
2792        if (id == CSSValueRight)
2793            percent = 100;
2794        else if (id == CSSValueCenter)
2795            percent = 50;
2796        return primitiveValueCache()->createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2797    }
2798    if (validUnit(valueList->current(), FPercent | FLength, m_strict))
2799        return primitiveValueCache()->createValue(valueList->current()->fValue,
2800                                                  (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
2801    return 0;
2802}
2803
2804PassRefPtr<CSSValue> CSSParser::parseFillPositionY(CSSParserValueList* valueList)
2805{
2806    int id = valueList->current()->id;
2807    if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
2808        int percent = 0;
2809        if (id == CSSValueBottom)
2810            percent = 100;
2811        else if (id == CSSValueCenter)
2812            percent = 50;
2813        return primitiveValueCache()->createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2814    }
2815    if (validUnit(valueList->current(), FPercent | FLength, m_strict))
2816        return primitiveValueCache()->createValue(valueList->current()->fValue,
2817                                                  (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
2818    return 0;
2819}
2820
2821PassRefPtr<CSSValue> CSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag)
2822{
2823    int id = valueList->current()->id;
2824    if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
2825        int percent = 0;
2826        if (id == CSSValueLeft || id == CSSValueRight) {
2827            if (cumulativeFlags & XFillPosition)
2828                return 0;
2829            cumulativeFlags |= XFillPosition;
2830            individualFlag = XFillPosition;
2831            if (id == CSSValueRight)
2832                percent = 100;
2833        }
2834        else if (id == CSSValueTop || id == CSSValueBottom) {
2835            if (cumulativeFlags & YFillPosition)
2836                return 0;
2837            cumulativeFlags |= YFillPosition;
2838            individualFlag = YFillPosition;
2839            if (id == CSSValueBottom)
2840                percent = 100;
2841        } else if (id == CSSValueCenter) {
2842            // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
2843            percent = 50;
2844            cumulativeFlags |= AmbiguousFillPosition;
2845            individualFlag = AmbiguousFillPosition;
2846        }
2847        return primitiveValueCache()->createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2848    }
2849    if (validUnit(valueList->current(), FPercent | FLength, m_strict)) {
2850        if (!cumulativeFlags) {
2851            cumulativeFlags |= XFillPosition;
2852            individualFlag = XFillPosition;
2853        } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
2854            cumulativeFlags |= YFillPosition;
2855            individualFlag = YFillPosition;
2856        } else
2857            return 0;
2858        return primitiveValueCache()->createValue(valueList->current()->fValue,
2859                                                  (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
2860    }
2861    return 0;
2862}
2863
2864void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
2865{
2866    CSSParserValue* value = valueList->current();
2867
2868    // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
2869    unsigned cumulativeFlags = 0;
2870    FillPositionFlag value1Flag = InvalidFillPosition;
2871    FillPositionFlag value2Flag = InvalidFillPosition;
2872    value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
2873    if (!value1)
2874        return;
2875
2876    // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
2877    // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
2878    // value was explicitly specified for our property.
2879    value = valueList->next();
2880
2881    // First check for the comma.  If so, we are finished parsing this value or value pair.
2882    if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
2883        value = 0;
2884
2885    if (value) {
2886        value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
2887        if (value2)
2888            valueList->next();
2889        else {
2890            if (!inShorthand()) {
2891                value1.clear();
2892                return;
2893            }
2894        }
2895    }
2896
2897    if (!value2)
2898        // Only one value was specified.  If that value was not a keyword, then it sets the x position, and the y position
2899        // is simply 50%.  This is our default.
2900        // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
2901        // For left/right/center, the default of 50% in the y is still correct.
2902        value2 = primitiveValueCache()->createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
2903
2904    if (value1Flag == YFillPosition || value2Flag == XFillPosition)
2905        value1.swap(value2);
2906}
2907
2908void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
2909{
2910    CSSParserValue* value = m_valueList->current();
2911
2912    int id = m_valueList->current()->id;
2913    if (id == CSSValueRepeatX) {
2914        m_implicitShorthand = true;
2915        value1 = primitiveValueCache()->createIdentifierValue(CSSValueRepeat);
2916        value2 = primitiveValueCache()->createIdentifierValue(CSSValueNoRepeat);
2917        m_valueList->next();
2918        return;
2919    }
2920    if (id == CSSValueRepeatY) {
2921        m_implicitShorthand = true;
2922        value1 = primitiveValueCache()->createIdentifierValue(CSSValueNoRepeat);
2923        value2 = primitiveValueCache()->createIdentifierValue(CSSValueRepeat);
2924        m_valueList->next();
2925        return;
2926    }
2927    if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
2928        value1 = primitiveValueCache()->createIdentifierValue(id);
2929    else {
2930        value1 = 0;
2931        return;
2932    }
2933
2934    value = m_valueList->next();
2935
2936    // First check for the comma.  If so, we are finished parsing this value or value pair.
2937    if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
2938        value = 0;
2939
2940    if (value)
2941        id = m_valueList->current()->id;
2942
2943    if (value && (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)) {
2944        value2 = primitiveValueCache()->createIdentifierValue(id);
2945        m_valueList->next();
2946    } else {
2947        // If only one value was specified, value2 is the same as value1.
2948        m_implicitShorthand = true;
2949        value2 = primitiveValueCache()->createIdentifierValue(static_cast<CSSPrimitiveValue*>(value1.get())->getIdent());
2950    }
2951}
2952
2953PassRefPtr<CSSValue> CSSParser::parseFillSize(int propId, bool& allowComma)
2954{
2955    allowComma = true;
2956    CSSParserValue* value = m_valueList->current();
2957
2958    if (value->id == CSSValueContain || value->id == CSSValueCover)
2959        return primitiveValueCache()->createIdentifierValue(value->id);
2960
2961    RefPtr<CSSPrimitiveValue> parsedValue1;
2962
2963    if (value->id == CSSValueAuto)
2964        parsedValue1 = primitiveValueCache()->createValue(0, CSSPrimitiveValue::CSS_UNKNOWN);
2965    else {
2966        if (!validUnit(value, FLength | FPercent, m_strict))
2967            return 0;
2968        parsedValue1 = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2969    }
2970
2971    CSSPropertyID property = static_cast<CSSPropertyID>(propId);
2972    RefPtr<CSSPrimitiveValue> parsedValue2;
2973    if ((value = m_valueList->next())) {
2974        if (value->id == CSSValueAuto)
2975            parsedValue2 = primitiveValueCache()->createValue(0, CSSPrimitiveValue::CSS_UNKNOWN);
2976        else if (value->unit == CSSParserValue::Operator && value->iValue == ',')
2977            allowComma = false;
2978        else {
2979            if (!validUnit(value, FLength | FPercent, m_strict))
2980                return 0;
2981            parsedValue2 = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2982        }
2983    }
2984    if (!parsedValue2) {
2985        if (property == CSSPropertyWebkitBackgroundSize || property == CSSPropertyWebkitMaskSize)
2986            parsedValue2 = parsedValue1;
2987        else
2988            parsedValue2 = primitiveValueCache()->createValue(0, CSSPrimitiveValue::CSS_UNKNOWN);
2989    }
2990
2991    return primitiveValueCache()->createValue(Pair::create(parsedValue1.release(), parsedValue2.release()));
2992}
2993
2994bool CSSParser::parseFillProperty(int propId, int& propId1, int& propId2,
2995                                  RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
2996{
2997    RefPtr<CSSValueList> values;
2998    RefPtr<CSSValueList> values2;
2999    CSSParserValue* val;
3000    RefPtr<CSSValue> value;
3001    RefPtr<CSSValue> value2;
3002
3003    bool allowComma = false;
3004
3005    retValue1 = retValue2 = 0;
3006    propId1 = propId;
3007    propId2 = propId;
3008    if (propId == CSSPropertyBackgroundPosition) {
3009        propId1 = CSSPropertyBackgroundPositionX;
3010        propId2 = CSSPropertyBackgroundPositionY;
3011    } else if (propId == CSSPropertyWebkitMaskPosition) {
3012        propId1 = CSSPropertyWebkitMaskPositionX;
3013        propId2 = CSSPropertyWebkitMaskPositionY;
3014    } else if (propId == CSSPropertyBackgroundRepeat) {
3015        propId1 = CSSPropertyBackgroundRepeatX;
3016        propId2 = CSSPropertyBackgroundRepeatY;
3017    } else if (propId == CSSPropertyWebkitMaskRepeat) {
3018        propId1 = CSSPropertyWebkitMaskRepeatX;
3019        propId2 = CSSPropertyWebkitMaskRepeatY;
3020    }
3021
3022    while ((val = m_valueList->current())) {
3023        RefPtr<CSSValue> currValue;
3024        RefPtr<CSSValue> currValue2;
3025
3026        if (allowComma) {
3027            if (val->unit != CSSParserValue::Operator || val->iValue != ',')
3028                return false;
3029            m_valueList->next();
3030            allowComma = false;
3031        } else {
3032            allowComma = true;
3033            switch (propId) {
3034                case CSSPropertyBackgroundColor:
3035                    currValue = parseBackgroundColor();
3036                    if (currValue)
3037                        m_valueList->next();
3038                    break;
3039                case CSSPropertyBackgroundAttachment:
3040                case CSSPropertyWebkitMaskAttachment:
3041                    if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
3042                        currValue = primitiveValueCache()->createIdentifierValue(val->id);
3043                        m_valueList->next();
3044                    }
3045                    break;
3046                case CSSPropertyBackgroundImage:
3047                case CSSPropertyWebkitMaskImage:
3048                    if (parseFillImage(currValue))
3049                        m_valueList->next();
3050                    break;
3051                case CSSPropertyWebkitBackgroundClip:
3052                case CSSPropertyWebkitBackgroundOrigin:
3053                case CSSPropertyWebkitMaskClip:
3054                case CSSPropertyWebkitMaskOrigin:
3055                    // The first three values here are deprecated and do not apply to the version of the property that has
3056                    // the -webkit- prefix removed.
3057                    if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
3058                        val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
3059                        ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
3060                         (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
3061                        currValue = primitiveValueCache()->createIdentifierValue(val->id);
3062                        m_valueList->next();
3063                    }
3064                    break;
3065                case CSSPropertyBackgroundClip:
3066                    if (parseBackgroundClip(val, currValue, primitiveValueCache()))
3067                        m_valueList->next();
3068                    break;
3069                case CSSPropertyBackgroundOrigin:
3070                    if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
3071                        currValue = primitiveValueCache()->createIdentifierValue(val->id);
3072                        m_valueList->next();
3073                    }
3074                    break;
3075                case CSSPropertyBackgroundPosition:
3076                case CSSPropertyWebkitMaskPosition:
3077                    parseFillPosition(m_valueList, currValue, currValue2);
3078                    // parseFillPosition advances the m_valueList pointer
3079                    break;
3080                case CSSPropertyBackgroundPositionX:
3081                case CSSPropertyWebkitMaskPositionX: {
3082                    currValue = parseFillPositionX(m_valueList);
3083                    if (currValue)
3084                        m_valueList->next();
3085                    break;
3086                }
3087                case CSSPropertyBackgroundPositionY:
3088                case CSSPropertyWebkitMaskPositionY: {
3089                    currValue = parseFillPositionY(m_valueList);
3090                    if (currValue)
3091                        m_valueList->next();
3092                    break;
3093                }
3094                case CSSPropertyWebkitBackgroundComposite:
3095                case CSSPropertyWebkitMaskComposite:
3096                    if ((val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) || val->id == CSSValueHighlight) {
3097                        currValue = primitiveValueCache()->createIdentifierValue(val->id);
3098                        m_valueList->next();
3099                    }
3100                    break;
3101                case CSSPropertyBackgroundRepeat:
3102                case CSSPropertyWebkitMaskRepeat:
3103                    parseFillRepeat(currValue, currValue2);
3104                    // parseFillRepeat advances the m_valueList pointer
3105                    break;
3106                case CSSPropertyBackgroundSize:
3107                case CSSPropertyWebkitBackgroundSize:
3108                case CSSPropertyWebkitMaskSize: {
3109                    currValue = parseFillSize(propId, allowComma);
3110                    if (currValue)
3111                        m_valueList->next();
3112                    break;
3113                }
3114            }
3115            if (!currValue)
3116                return false;
3117
3118            if (value && !values) {
3119                values = CSSValueList::createCommaSeparated();
3120                values->append(value.release());
3121            }
3122
3123            if (value2 && !values2) {
3124                values2 = CSSValueList::createCommaSeparated();
3125                values2->append(value2.release());
3126            }
3127
3128            if (values)
3129                values->append(currValue.release());
3130            else
3131                value = currValue.release();
3132            if (currValue2) {
3133                if (values2)
3134                    values2->append(currValue2.release());
3135                else
3136                    value2 = currValue2.release();
3137            }
3138        }
3139
3140        // When parsing any fill shorthand property, we let it handle building up the lists for all
3141        // properties.
3142        if (inShorthand())
3143            break;
3144    }
3145
3146    if (values && values->length()) {
3147        retValue1 = values.release();
3148        if (values2 && values2->length())
3149            retValue2 = values2.release();
3150        return true;
3151    }
3152    if (value) {
3153        retValue1 = value.release();
3154        retValue2 = value2.release();
3155        return true;
3156    }
3157    return false;
3158}
3159
3160PassRefPtr<CSSValue> CSSParser::parseAnimationDelay()
3161{
3162    CSSParserValue* value = m_valueList->current();
3163    if (validUnit(value, FTime, m_strict))
3164        return primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
3165    return 0;
3166}
3167
3168PassRefPtr<CSSValue> CSSParser::parseAnimationDirection()
3169{
3170    CSSParserValue* value = m_valueList->current();
3171    if (value->id == CSSValueNormal || value->id == CSSValueAlternate)
3172        return primitiveValueCache()->createIdentifierValue(value->id);
3173    return 0;
3174}
3175
3176PassRefPtr<CSSValue> CSSParser::parseAnimationDuration()
3177{
3178    CSSParserValue* value = m_valueList->current();
3179    if (validUnit(value, FTime | FNonNeg, m_strict))
3180        return primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
3181    return 0;
3182}
3183
3184PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode()
3185{
3186    CSSParserValue* value = m_valueList->current();
3187    if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
3188        return primitiveValueCache()->createIdentifierValue(value->id);
3189    return 0;
3190}
3191
3192PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount()
3193{
3194    CSSParserValue* value = m_valueList->current();
3195    if (value->id == CSSValueInfinite)
3196        return primitiveValueCache()->createIdentifierValue(value->id);
3197    if (validUnit(value, FInteger | FNonNeg, m_strict))
3198        return primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
3199    return 0;
3200}
3201
3202PassRefPtr<CSSValue> CSSParser::parseAnimationName()
3203{
3204    CSSParserValue* value = m_valueList->current();
3205    if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
3206        if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value->string, "none"))) {
3207            return primitiveValueCache()->createIdentifierValue(CSSValueNone);
3208        } else {
3209            return primitiveValueCache()->createValue(value->string, CSSPrimitiveValue::CSS_STRING);
3210        }
3211    }
3212    return 0;
3213}
3214
3215PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState()
3216{
3217    CSSParserValue* value = m_valueList->current();
3218    if (value->id == CSSValueRunning || value->id == CSSValuePaused)
3219        return primitiveValueCache()->createIdentifierValue(value->id);
3220    return 0;
3221}
3222
3223PassRefPtr<CSSValue> CSSParser::parseAnimationProperty()
3224{
3225    CSSParserValue* value = m_valueList->current();
3226    if (value->unit != CSSPrimitiveValue::CSS_IDENT)
3227        return 0;
3228    int result = cssPropertyID(value->string);
3229    if (result)
3230        return primitiveValueCache()->createIdentifierValue(result);
3231    if (equalIgnoringCase(value->string, "all"))
3232        return primitiveValueCache()->createIdentifierValue(CSSValueAll);
3233    if (equalIgnoringCase(value->string, "none"))
3234        return primitiveValueCache()->createIdentifierValue(CSSValueNone);
3235    return 0;
3236}
3237
3238bool CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
3239{
3240    parseFillPosition(m_valueList, value1, value2);
3241
3242    // now get z
3243    if (m_valueList->current()) {
3244        if (validUnit(m_valueList->current(), FLength, m_strict)) {
3245            value3 = primitiveValueCache()->createValue(m_valueList->current()->fValue,
3246                                             (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit);
3247            m_valueList->next();
3248            return true;
3249        }
3250        return false;
3251    }
3252    return true;
3253}
3254
3255bool CSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
3256{
3257    CSSParserValue* v = args->current();
3258    if (!validUnit(v, FNumber, m_strict))
3259        return false;
3260    result = v->fValue;
3261    if (result < 0 || result > 1.0)
3262        return false;
3263    v = args->next();
3264    if (!v)
3265        // The last number in the function has no comma after it, so we're done.
3266        return true;
3267    if (v->unit != CSSParserValue::Operator && v->iValue != ',')
3268        return false;
3269    v = args->next();
3270    return true;
3271}
3272
3273PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction()
3274{
3275    CSSParserValue* value = m_valueList->current();
3276    if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
3277        || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd)
3278        return primitiveValueCache()->createIdentifierValue(value->id);
3279
3280    // We must be a function.
3281    if (value->unit != CSSParserValue::Function)
3282        return 0;
3283
3284    CSSParserValueList* args = value->function->args.get();
3285
3286    if (equalIgnoringCase(value->function->name, "steps(")) {
3287        // For steps, 1 or 2 params must be specified (comma-separated)
3288        if (!args || (args->size() != 1 && args->size() != 3))
3289            return 0;
3290
3291        // There are two values.
3292        int numSteps;
3293        bool stepAtStart = false;
3294
3295        CSSParserValue* v = args->current();
3296        if (!validUnit(v, FInteger, m_strict))
3297            return 0;
3298        numSteps = (int) min(v->fValue, (double)INT_MAX);
3299        if (numSteps < 1)
3300            return 0;
3301        v = args->next();
3302
3303        if (v) {
3304            // There is a comma so we need to parse the second value
3305            if (v->unit != CSSParserValue::Operator && v->iValue != ',')
3306                return 0;
3307            v = args->next();
3308            if (v->id != CSSValueStart && v->id != CSSValueEnd)
3309                return 0;
3310            stepAtStart = v->id == CSSValueStart;
3311        }
3312
3313        return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart);
3314    }
3315
3316    if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
3317        // For cubic bezier, 4 values must be specified.
3318        if (!args || args->size() != 7)
3319            return 0;
3320
3321        // There are two points specified.  The values must be between 0 and 1.
3322        double x1, y1, x2, y2;
3323
3324        if (!parseCubicBezierTimingFunctionValue(args, x1))
3325            return 0;
3326        if (!parseCubicBezierTimingFunctionValue(args, y1))
3327            return 0;
3328        if (!parseCubicBezierTimingFunctionValue(args, x2))
3329            return 0;
3330        if (!parseCubicBezierTimingFunctionValue(args, y2))
3331            return 0;
3332
3333        return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
3334    }
3335
3336    return 0;
3337}
3338
3339bool CSSParser::parseAnimationProperty(int propId, RefPtr<CSSValue>& result)
3340{
3341    RefPtr<CSSValueList> values;
3342    CSSParserValue* val;
3343    RefPtr<CSSValue> value;
3344    bool allowComma = false;
3345
3346    result = 0;
3347
3348    while ((val = m_valueList->current())) {
3349        RefPtr<CSSValue> currValue;
3350        if (allowComma) {
3351            if (val->unit != CSSParserValue::Operator || val->iValue != ',')
3352                return false;
3353            m_valueList->next();
3354            allowComma = false;
3355        }
3356        else {
3357            switch (propId) {
3358                case CSSPropertyWebkitAnimationDelay:
3359                case CSSPropertyWebkitTransitionDelay:
3360                    currValue = parseAnimationDelay();
3361                    if (currValue)
3362                        m_valueList->next();
3363                    break;
3364                case CSSPropertyWebkitAnimationDirection:
3365                    currValue = parseAnimationDirection();
3366                    if (currValue)
3367                        m_valueList->next();
3368                    break;
3369                case CSSPropertyWebkitAnimationDuration:
3370                case CSSPropertyWebkitTransitionDuration:
3371                    currValue = parseAnimationDuration();
3372                    if (currValue)
3373                        m_valueList->next();
3374                    break;
3375                case CSSPropertyWebkitAnimationFillMode:
3376                    currValue = parseAnimationFillMode();
3377                    if (currValue)
3378                        m_valueList->next();
3379                    break;
3380                case CSSPropertyWebkitAnimationIterationCount:
3381                    currValue = parseAnimationIterationCount();
3382                    if (currValue)
3383                        m_valueList->next();
3384                    break;
3385                case CSSPropertyWebkitAnimationName:
3386                    currValue = parseAnimationName();
3387                    if (currValue)
3388                        m_valueList->next();
3389                    break;
3390                case CSSPropertyWebkitAnimationPlayState:
3391                    currValue = parseAnimationPlayState();
3392                    if (currValue)
3393                        m_valueList->next();
3394                    break;
3395                case CSSPropertyWebkitTransitionProperty:
3396                    currValue = parseAnimationProperty();
3397                    if (currValue)
3398                        m_valueList->next();
3399                    break;
3400                case CSSPropertyWebkitAnimationTimingFunction:
3401                case CSSPropertyWebkitTransitionTimingFunction:
3402                    currValue = parseAnimationTimingFunction();
3403                    if (currValue)
3404                        m_valueList->next();
3405                    break;
3406            }
3407
3408            if (!currValue)
3409                return false;
3410
3411            if (value && !values) {
3412                values = CSSValueList::createCommaSeparated();
3413                values->append(value.release());
3414            }
3415
3416            if (values)
3417                values->append(currValue.release());
3418            else
3419                value = currValue.release();
3420
3421            allowComma = true;
3422        }
3423
3424        // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
3425        // properties.
3426        if (inShorthand())
3427            break;
3428    }
3429
3430    if (values && values->length()) {
3431        result = values.release();
3432        return true;
3433    }
3434    if (value) {
3435        result = value.release();
3436        return true;
3437    }
3438    return false;
3439}
3440
3441
3442
3443#if ENABLE(DASHBOARD_SUPPORT)
3444
3445#define DASHBOARD_REGION_NUM_PARAMETERS  6
3446#define DASHBOARD_REGION_SHORT_NUM_PARAMETERS  2
3447
3448static CSSParserValue* skipCommaInDashboardRegion(CSSParserValueList *args)
3449{
3450    if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) ||
3451         args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
3452        CSSParserValue* current = args->current();
3453        if (current->unit == CSSParserValue::Operator && current->iValue == ',')
3454            return args->next();
3455    }
3456    return args->current();
3457}
3458
3459bool CSSParser::parseDashboardRegions(int propId, bool important)
3460{
3461    bool valid = true;
3462
3463    CSSParserValue* value = m_valueList->current();
3464
3465    if (value->id == CSSValueNone) {
3466        if (m_valueList->next())
3467            return false;
3468        addProperty(propId, primitiveValueCache()->createIdentifierValue(value->id), important);
3469        return valid;
3470    }
3471
3472    RefPtr<DashboardRegion> firstRegion = DashboardRegion::create();
3473    DashboardRegion* region = 0;
3474
3475    while (value) {
3476        if (region == 0) {
3477            region = firstRegion.get();
3478        } else {
3479            RefPtr<DashboardRegion> nextRegion = DashboardRegion::create();
3480            region->m_next = nextRegion;
3481            region = nextRegion.get();
3482        }
3483
3484        if (value->unit != CSSParserValue::Function) {
3485            valid = false;
3486            break;
3487        }
3488
3489        // Commas count as values, so allow:
3490        // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
3491        // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
3492        // also allow
3493        // dashboard-region(label, type) or dashboard-region(label type)
3494        // dashboard-region(label, type) or dashboard-region(label type)
3495        CSSParserValueList* args = value->function->args.get();
3496        if (!equalIgnoringCase(value->function->name, "dashboard-region(") || !args) {
3497            valid = false;
3498            break;
3499        }
3500
3501        int numArgs = args->size();
3502        if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) &&
3503            (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))) {
3504            valid = false;
3505            break;
3506        }
3507
3508        // First arg is a label.
3509        CSSParserValue* arg = args->current();
3510        if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
3511            valid = false;
3512            break;
3513        }
3514
3515        region->m_label = arg->string;
3516
3517        // Second arg is a type.
3518        arg = args->next();
3519        arg = skipCommaInDashboardRegion(args);
3520        if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
3521            valid = false;
3522            break;
3523        }
3524
3525        if (equalIgnoringCase(arg->string, "circle"))
3526            region->m_isCircle = true;
3527        else if (equalIgnoringCase(arg->string, "rectangle"))
3528            region->m_isRectangle = true;
3529        else {
3530            valid = false;
3531            break;
3532        }
3533
3534        region->m_geometryType = arg->string;
3535
3536        if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
3537            // This originally used CSSValueInvalid by accident. It might be more logical to use something else.
3538            RefPtr<CSSPrimitiveValue> amount = primitiveValueCache()->createIdentifierValue(CSSValueInvalid);
3539
3540            region->setTop(amount);
3541            region->setRight(amount);
3542            region->setBottom(amount);
3543            region->setLeft(amount);
3544        } else {
3545            // Next four arguments must be offset numbers
3546            int i;
3547            for (i = 0; i < 4; i++) {
3548                arg = args->next();
3549                arg = skipCommaInDashboardRegion(args);
3550
3551                valid = arg->id == CSSValueAuto || validUnit(arg, FLength, m_strict);
3552                if (!valid)
3553                    break;
3554
3555                RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ?
3556                    primitiveValueCache()->createIdentifierValue(CSSValueAuto) :
3557                    primitiveValueCache()->createValue(arg->fValue, (CSSPrimitiveValue::UnitTypes) arg->unit);
3558
3559                if (i == 0)
3560                    region->setTop(amount);
3561                else if (i == 1)
3562                    region->setRight(amount);
3563                else if (i == 2)
3564                    region->setBottom(amount);
3565                else
3566                    region->setLeft(amount);
3567            }
3568        }
3569
3570        if (args->next())
3571            return false;
3572
3573        value = m_valueList->next();
3574    }
3575
3576    if (valid)
3577        addProperty(propId, primitiveValueCache()->createValue(firstRegion.release()), important);
3578
3579    return valid;
3580}
3581
3582#endif /* ENABLE(DASHBOARD_SUPPORT) */
3583
3584PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
3585{
3586    unsigned numArgs = args->size();
3587    if (counters && numArgs != 3 && numArgs != 5)
3588        return 0;
3589    if (!counters && numArgs != 1 && numArgs != 3)
3590        return 0;
3591
3592    CSSParserValue* i = args->current();
3593    if (i->unit != CSSPrimitiveValue::CSS_IDENT)
3594        return 0;
3595    RefPtr<CSSPrimitiveValue> identifier = primitiveValueCache()->createValue(i->string, CSSPrimitiveValue::CSS_STRING);
3596
3597    RefPtr<CSSPrimitiveValue> separator;
3598    if (!counters)
3599        separator = primitiveValueCache()->createValue(String(), CSSPrimitiveValue::CSS_STRING);
3600    else {
3601        i = args->next();
3602        if (i->unit != CSSParserValue::Operator || i->iValue != ',')
3603            return 0;
3604
3605        i = args->next();
3606        if (i->unit != CSSPrimitiveValue::CSS_STRING)
3607            return 0;
3608
3609        separator = primitiveValueCache()->createValue(i->string, (CSSPrimitiveValue::UnitTypes) i->unit);
3610    }
3611
3612    RefPtr<CSSPrimitiveValue> listStyle;
3613    i = args->next();
3614    if (!i) // Make the list style default decimal
3615        listStyle = primitiveValueCache()->createValue(CSSValueDecimal - CSSValueDisc, CSSPrimitiveValue::CSS_NUMBER);
3616    else {
3617        if (i->unit != CSSParserValue::Operator || i->iValue != ',')
3618            return 0;
3619
3620        i = args->next();
3621        if (i->unit != CSSPrimitiveValue::CSS_IDENT)
3622            return 0;
3623
3624        short ls = 0;
3625        if (i->id == CSSValueNone)
3626            ls = CSSValueKatakanaIroha - CSSValueDisc + 1;
3627        else if (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha)
3628            ls = i->id - CSSValueDisc;
3629        else
3630            return 0;
3631
3632        listStyle = primitiveValueCache()->createValue(ls, (CSSPrimitiveValue::UnitTypes) i->unit);
3633    }
3634
3635    return primitiveValueCache()->createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
3636}
3637
3638bool CSSParser::parseShape(int propId, bool important)
3639{
3640    CSSParserValue* value = m_valueList->current();
3641    CSSParserValueList* args = value->function->args.get();
3642
3643    if (!equalIgnoringCase(value->function->name, "rect(") || !args)
3644        return false;
3645
3646    // rect(t, r, b, l) || rect(t r b l)
3647    if (args->size() != 4 && args->size() != 7)
3648        return false;
3649    RefPtr<Rect> rect = Rect::create();
3650    bool valid = true;
3651    int i = 0;
3652    CSSParserValue* a = args->current();
3653    while (a) {
3654        valid = a->id == CSSValueAuto || validUnit(a, FLength, m_strict);
3655        if (!valid)
3656            break;
3657        RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
3658            primitiveValueCache()->createIdentifierValue(CSSValueAuto) :
3659            primitiveValueCache()->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
3660        if (i == 0)
3661            rect->setTop(length);
3662        else if (i == 1)
3663            rect->setRight(length);
3664        else if (i == 2)
3665            rect->setBottom(length);
3666        else
3667            rect->setLeft(length);
3668        a = args->next();
3669        if (a && args->size() == 7) {
3670            if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
3671                a = args->next();
3672            } else {
3673                valid = false;
3674                break;
3675            }
3676        }
3677        i++;
3678    }
3679    if (valid) {
3680        addProperty(propId, primitiveValueCache()->createValue(rect.release()), important);
3681        m_valueList->next();
3682        return true;
3683    }
3684    return false;
3685}
3686
3687// [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
3688bool CSSParser::parseFont(bool important)
3689{
3690    bool valid = true;
3691    CSSParserValue *value = m_valueList->current();
3692    RefPtr<FontValue> font = FontValue::create();
3693    // optional font-style, font-variant and font-weight
3694    while (value) {
3695        int id = value->id;
3696        if (id) {
3697            if (id == CSSValueNormal) {
3698                // do nothing, it's the inital value for all three
3699            } else if (id == CSSValueItalic || id == CSSValueOblique) {
3700                if (font->style)
3701                    return false;
3702                font->style = primitiveValueCache()->createIdentifierValue(id);
3703            } else if (id == CSSValueSmallCaps) {
3704                if (font->variant)
3705                    return false;
3706                font->variant = primitiveValueCache()->createIdentifierValue(id);
3707            } else if (id >= CSSValueBold && id <= CSSValueLighter) {
3708                if (font->weight)
3709                    return false;
3710                font->weight = primitiveValueCache()->createIdentifierValue(id);
3711            } else {
3712                valid = false;
3713            }
3714        } else if (!font->weight && validUnit(value, FInteger | FNonNeg, true)) {
3715            int weight = (int)value->fValue;
3716            int val = 0;
3717            if (weight == 100)
3718                val = CSSValue100;
3719            else if (weight == 200)
3720                val = CSSValue200;
3721            else if (weight == 300)
3722                val = CSSValue300;
3723            else if (weight == 400)
3724                val = CSSValue400;
3725            else if (weight == 500)
3726                val = CSSValue500;
3727            else if (weight == 600)
3728                val = CSSValue600;
3729            else if (weight == 700)
3730                val = CSSValue700;
3731            else if (weight == 800)
3732                val = CSSValue800;
3733            else if (weight == 900)
3734                val = CSSValue900;
3735
3736            if (val)
3737                font->weight = primitiveValueCache()->createIdentifierValue(val);
3738            else
3739                valid = false;
3740        } else {
3741            valid = false;
3742        }
3743        if (!valid)
3744            break;
3745        value = m_valueList->next();
3746    }
3747    if (!value)
3748        return false;
3749
3750    // set undefined values to default
3751    if (!font->style)
3752        font->style = primitiveValueCache()->createIdentifierValue(CSSValueNormal);
3753    if (!font->variant)
3754        font->variant = primitiveValueCache()->createIdentifierValue(CSSValueNormal);
3755    if (!font->weight)
3756        font->weight = primitiveValueCache()->createIdentifierValue(CSSValueNormal);
3757
3758    // now a font size _must_ come
3759    // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
3760    if (value->id >= CSSValueXxSmall && value->id <= CSSValueLarger)
3761        font->size = primitiveValueCache()->createIdentifierValue(value->id);
3762    else if (validUnit(value, FLength | FPercent | FNonNeg, m_strict))
3763        font->size = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
3764    value = m_valueList->next();
3765    if (!font->size || !value)
3766        return false;
3767
3768    if (value->unit == CSSParserValue::Operator && value->iValue == '/') {
3769        // line-height
3770        value = m_valueList->next();
3771        if (!value)
3772            return false;
3773        if (value->id == CSSValueNormal) {
3774            // default value, nothing to do
3775        } else if (validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict))
3776            font->lineHeight = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
3777        else
3778            return false;
3779        value = m_valueList->next();
3780        if (!value)
3781            return false;
3782    }
3783
3784    if (!font->lineHeight)
3785        font->lineHeight = primitiveValueCache()->createIdentifierValue(CSSValueNormal);
3786
3787    // font family must come now
3788    font->family = parseFontFamily();
3789
3790    if (m_valueList->current() || !font->family)
3791        return false;
3792
3793    addProperty(CSSPropertyFont, font.release(), important);
3794    return true;
3795}
3796
3797PassRefPtr<CSSValueList> CSSParser::parseFontFamily()
3798{
3799    RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
3800    CSSParserValue* value = m_valueList->current();
3801
3802    FontFamilyValue* currFamily = 0;
3803    while (value) {
3804        CSSParserValue* nextValue = m_valueList->next();
3805        bool nextValBreaksFont = !nextValue ||
3806                                 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
3807        bool nextValIsFontName = nextValue &&
3808            ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
3809            (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
3810
3811        if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
3812            if (currFamily)
3813                currFamily->appendSpaceSeparated(value->string.characters, value->string.length);
3814            else if (nextValBreaksFont || !nextValIsFontName)
3815                list->append(primitiveValueCache()->createIdentifierValue(value->id));
3816            else {
3817                RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string);
3818                currFamily = newFamily.get();
3819                list->append(newFamily.release());
3820            }
3821        } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
3822            // Strings never share in a family name.
3823            currFamily = 0;
3824            list->append(FontFamilyValue::create(value->string));
3825        } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
3826            if (currFamily)
3827                currFamily->appendSpaceSeparated(value->string.characters, value->string.length);
3828            else if (nextValBreaksFont || !nextValIsFontName)
3829                list->append(FontFamilyValue::create(value->string));
3830            else {
3831                RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string);
3832                currFamily = newFamily.get();
3833                list->append(newFamily.release());
3834            }
3835        } else {
3836            break;
3837        }
3838
3839        if (!nextValue)
3840            break;
3841
3842        if (nextValBreaksFont) {
3843            value = m_valueList->next();
3844            currFamily = 0;
3845        }
3846        else if (nextValIsFontName)
3847            value = nextValue;
3848        else
3849            break;
3850    }
3851    if (!list->length())
3852        list = 0;
3853    return list.release();
3854}
3855
3856bool CSSParser::parseFontStyle(bool important)
3857{
3858    RefPtr<CSSValueList> values;
3859    if (m_valueList->size() > 1)
3860        values = CSSValueList::createCommaSeparated();
3861    CSSParserValue* val;
3862    bool expectComma = false;
3863    while ((val = m_valueList->current())) {
3864        RefPtr<CSSPrimitiveValue> parsedValue;
3865        if (!expectComma) {
3866            expectComma = true;
3867            if (val->id == CSSValueNormal || val->id == CSSValueItalic || val->id == CSSValueOblique)
3868                parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
3869            else if (val->id == CSSValueAll && !values) {
3870                // 'all' is only allowed in @font-face and with no other values. Make a value list to
3871                // indicate that we are in the @font-face case.
3872                values = CSSValueList::createCommaSeparated();
3873                parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
3874            }
3875        } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3876            expectComma = false;
3877            m_valueList->next();
3878            continue;
3879        }
3880
3881        if (!parsedValue)
3882            return false;
3883
3884        m_valueList->next();
3885
3886        if (values)
3887            values->append(parsedValue.release());
3888        else {
3889            addProperty(CSSPropertyFontStyle, parsedValue.release(), important);
3890            return true;
3891        }
3892    }
3893
3894    if (values && values->length()) {
3895        m_hasFontFaceOnlyValues = true;
3896        addProperty(CSSPropertyFontStyle, values.release(), important);
3897        return true;
3898    }
3899
3900    return false;
3901}
3902
3903bool CSSParser::parseFontVariant(bool important)
3904{
3905    RefPtr<CSSValueList> values;
3906    if (m_valueList->size() > 1)
3907        values = CSSValueList::createCommaSeparated();
3908    CSSParserValue* val;
3909    bool expectComma = false;
3910    while ((val = m_valueList->current())) {
3911        RefPtr<CSSPrimitiveValue> parsedValue;
3912        if (!expectComma) {
3913            expectComma = true;
3914            if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
3915                parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
3916            else if (val->id == CSSValueAll && !values) {
3917                // 'all' is only allowed in @font-face and with no other values. Make a value list to
3918                // indicate that we are in the @font-face case.
3919                values = CSSValueList::createCommaSeparated();
3920                parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
3921            }
3922        } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3923            expectComma = false;
3924            m_valueList->next();
3925            continue;
3926        }
3927
3928        if (!parsedValue)
3929            return false;
3930
3931        m_valueList->next();
3932
3933        if (values)
3934            values->append(parsedValue.release());
3935        else {
3936            addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
3937            return true;
3938        }
3939    }
3940
3941    if (values && values->length()) {
3942        m_hasFontFaceOnlyValues = true;
3943        addProperty(CSSPropertyFontVariant, values.release(), important);
3944        return true;
3945    }
3946
3947    return false;
3948}
3949
3950bool CSSParser::parseFontWeight(bool important)
3951{
3952    RefPtr<CSSValueList> values;
3953    if (m_valueList->size() > 1)
3954        values = CSSValueList::createCommaSeparated();
3955    CSSParserValue* val;
3956    bool expectComma = false;
3957    while ((val = m_valueList->current())) {
3958        RefPtr<CSSPrimitiveValue> parsedValue;
3959        if (!expectComma) {
3960            expectComma = true;
3961            if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
3962                if (val->id >= CSSValueNormal && val->id <= CSSValue900)
3963                    parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
3964                else if (val->id == CSSValueAll && !values) {
3965                    // 'all' is only allowed in @font-face and with no other values. Make a value list to
3966                    // indicate that we are in the @font-face case.
3967                    values = CSSValueList::createCommaSeparated();
3968                    parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
3969                }
3970            } else if (validUnit(val, FInteger | FNonNeg, false)) {
3971                int weight = static_cast<int>(val->fValue);
3972                if (!(weight % 100) && weight >= 100 && weight <= 900)
3973                    parsedValue = primitiveValueCache()->createIdentifierValue(CSSValue100 + weight / 100 - 1);
3974            }
3975        } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3976            expectComma = false;
3977            m_valueList->next();
3978            continue;
3979        }
3980
3981        if (!parsedValue)
3982            return false;
3983
3984        m_valueList->next();
3985
3986        if (values)
3987            values->append(parsedValue.release());
3988        else {
3989            addProperty(CSSPropertyFontWeight, parsedValue.release(), important);
3990            return true;
3991        }
3992    }
3993
3994    if (values && values->length()) {
3995        m_hasFontFaceOnlyValues = true;
3996        addProperty(CSSPropertyFontWeight, values.release(), important);
3997        return true;
3998    }
3999
4000    return false;
4001}
4002
4003static bool isValidFormatFunction(CSSParserValue* val)
4004{
4005    CSSParserValueList* args = val->function->args.get();
4006    return equalIgnoringCase(val->function->name, "format(") && (args->current()->unit == CSSPrimitiveValue::CSS_STRING || args->current()->unit == CSSPrimitiveValue::CSS_IDENT);
4007}
4008
4009bool CSSParser::parseFontFaceSrc()
4010{
4011    RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
4012    CSSParserValue* val;
4013    bool expectComma = false;
4014    bool allowFormat = false;
4015    bool failed = false;
4016    RefPtr<CSSFontFaceSrcValue> uriValue;
4017    while ((val = m_valueList->current())) {
4018        RefPtr<CSSFontFaceSrcValue> parsedValue;
4019        if (val->unit == CSSPrimitiveValue::CSS_URI && !expectComma && m_styleSheet) {
4020            // FIXME: The completeURL call should be done when using the CSSFontFaceSrcValue,
4021            // not when creating it.
4022            parsedValue = CSSFontFaceSrcValue::create(m_styleSheet->completeURL(val->string));
4023            uriValue = parsedValue;
4024            allowFormat = true;
4025            expectComma = true;
4026        } else if (val->unit == CSSParserValue::Function) {
4027            // There are two allowed functions: local() and format().
4028            CSSParserValueList* args = val->function->args.get();
4029            if (args && args->size() == 1) {
4030                if (equalIgnoringCase(val->function->name, "local(") && !expectComma && (args->current()->unit == CSSPrimitiveValue::CSS_STRING || args->current()->unit == CSSPrimitiveValue::CSS_IDENT)) {
4031                    expectComma = true;
4032                    allowFormat = false;
4033                    CSSParserValue* a = args->current();
4034                    uriValue.clear();
4035                    parsedValue = CSSFontFaceSrcValue::createLocal(a->string);
4036                } else if (allowFormat && uriValue && isValidFormatFunction(val)) {
4037                    expectComma = true;
4038                    allowFormat = false;
4039                    uriValue->setFormat(args->current()->string);
4040                    uriValue.clear();
4041                    m_valueList->next();
4042                    continue;
4043                }
4044            }
4045        } else if (val->unit == CSSParserValue::Operator && val->iValue == ',' && expectComma) {
4046            expectComma = false;
4047            allowFormat = false;
4048            uriValue.clear();
4049            m_valueList->next();
4050            continue;
4051        }
4052
4053        if (parsedValue)
4054            values->append(parsedValue.release());
4055        else {
4056            failed = true;
4057            break;
4058        }
4059        m_valueList->next();
4060    }
4061
4062    if (values->length() && !failed) {
4063        addProperty(CSSPropertySrc, values.release(), m_important);
4064        m_valueList->next();
4065        return true;
4066    }
4067
4068    return false;
4069}
4070
4071bool CSSParser::parseFontFaceUnicodeRange()
4072{
4073    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
4074    bool failed = false;
4075    bool operatorExpected = false;
4076    for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
4077        if (operatorExpected) {
4078            if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
4079                continue;
4080            failed = true;
4081            break;
4082        }
4083        if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
4084            failed = true;
4085            break;
4086        }
4087
4088        String rangeString = m_valueList->current()->string;
4089        UChar32 from = 0;
4090        UChar32 to = 0;
4091        unsigned length = rangeString.length();
4092
4093        if (length < 3) {
4094            failed = true;
4095            break;
4096        }
4097
4098        unsigned i = 2;
4099        while (i < length) {
4100            UChar c = rangeString[i];
4101            if (c == '-' || c == '?')
4102                break;
4103            from *= 16;
4104            if (c >= '0' && c <= '9')
4105                from += c - '0';
4106            else if (c >= 'A' && c <= 'F')
4107                from += 10 + c - 'A';
4108            else if (c >= 'a' && c <= 'f')
4109                from += 10 + c - 'a';
4110            else {
4111                failed = true;
4112                break;
4113            }
4114            i++;
4115        }
4116        if (failed)
4117            break;
4118
4119        if (i == length)
4120            to = from;
4121        else if (rangeString[i] == '?') {
4122            unsigned span = 1;
4123            while (i < length && rangeString[i] == '?') {
4124                span *= 16;
4125                from *= 16;
4126                i++;
4127            }
4128            if (i < length)
4129                failed = true;
4130            to = from + span - 1;
4131        } else {
4132            if (length < i + 2) {
4133                failed = true;
4134                break;
4135            }
4136            i++;
4137            while (i < length) {
4138                UChar c = rangeString[i];
4139                to *= 16;
4140                if (c >= '0' && c <= '9')
4141                    to += c - '0';
4142                else if (c >= 'A' && c <= 'F')
4143                    to += 10 + c - 'A';
4144                else if (c >= 'a' && c <= 'f')
4145                    to += 10 + c - 'a';
4146                else {
4147                    failed = true;
4148                    break;
4149                }
4150                i++;
4151            }
4152            if (failed)
4153                break;
4154        }
4155        if (from <= to)
4156            values->append(CSSUnicodeRangeValue::create(from, to));
4157    }
4158    if (failed || !values->length())
4159        return false;
4160    addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
4161    return true;
4162}
4163
4164// Returns the number of characters which form a valid double
4165// and are terminated by the given terminator character
4166static int checkForValidDouble(const UChar* string, const UChar* end, const char terminator)
4167{
4168    int length = end - string;
4169    if (length < 1)
4170        return 0;
4171
4172    bool decimalMarkSeen = false;
4173    int processedLength = 0;
4174
4175    for (int i = 0; i < length; ++i) {
4176        if (string[i] == terminator) {
4177            processedLength = i;
4178            break;
4179        }
4180        if (!isASCIIDigit(string[i])) {
4181            if (!decimalMarkSeen && string[i] == '.')
4182                decimalMarkSeen = true;
4183            else
4184                return 0;
4185        }
4186    }
4187
4188    if (decimalMarkSeen && processedLength == 1)
4189        return 0;
4190
4191    return processedLength;
4192}
4193
4194// Returns the number of characters consumed for parsing a valid double
4195// terminated by the given terminator character
4196static int parseDouble(const UChar* string, const UChar* end, const char terminator, double& value)
4197{
4198    int length = checkForValidDouble(string, end, terminator);
4199    if (!length)
4200        return 0;
4201
4202    int position = 0;
4203    double localValue = 0;
4204
4205    // The consumed characters here are guaranteed to be
4206    // ASCII digits with or without a decimal mark
4207    for (; position < length; ++position) {
4208        if (string[position] == '.')
4209            break;
4210        localValue = localValue * 10 + string[position] - '0';
4211    }
4212
4213    if (++position == length) {
4214        value = localValue;
4215        return length;
4216    }
4217
4218    double fraction = 0;
4219    double scale = 1;
4220
4221    while (position < length && scale < MAX_SCALE) {
4222        fraction = fraction * 10 + string[position++] - '0';
4223        scale *= 10;
4224    }
4225
4226    value = localValue + fraction / scale;
4227    return length;
4228}
4229
4230static bool parseColorIntOrPercentage(const UChar*& string, const UChar* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
4231{
4232    const UChar* current = string;
4233    double localValue = 0;
4234    bool negative = false;
4235    while (current != end && isHTMLSpace(*current))
4236        current++;
4237    if (current != end && *current == '-') {
4238        negative = true;
4239        current++;
4240    }
4241    if (current == end || !isASCIIDigit(*current))
4242        return false;
4243    while (current != end && isASCIIDigit(*current)) {
4244        double newValue = localValue * 10 + *current++ - '0';
4245        if (newValue >= 255) {
4246            // Clamp values at 255.
4247            localValue = 255;
4248            while (current != end && isASCIIDigit(*current))
4249                ++current;
4250            break;
4251        }
4252        localValue = newValue;
4253    }
4254
4255    if (current == end)
4256        return false;
4257
4258    if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
4259        return false;
4260
4261    if (*current == '.') {
4262        // We already parsed the integral part, try to parse
4263        // the fraction part of the percentage value.
4264        double percentage = 0;
4265        int numCharactersParsed = parseDouble(current, end, '%', percentage);
4266        if (!numCharactersParsed)
4267            return false;
4268        current += numCharactersParsed;
4269        if (*current != '%')
4270            return false;
4271        localValue += percentage;
4272    }
4273
4274    if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
4275        return false;
4276
4277    if (*current == '%') {
4278        expect = CSSPrimitiveValue::CSS_PERCENTAGE;
4279        localValue = localValue / 100.0 * 256.0;
4280        // Clamp values at 255 for percentages over 100%
4281        if (localValue > 255)
4282            localValue = 255;
4283        current++;
4284    } else
4285        expect = CSSPrimitiveValue::CSS_NUMBER;
4286
4287    while (current != end && isHTMLSpace(*current))
4288        current++;
4289    if (current == end || *current++ != terminator)
4290        return false;
4291    // Clamp negative values at zero.
4292    value = negative ? 0 : static_cast<int>(localValue);
4293    string = current;
4294    return true;
4295}
4296
4297static inline bool isTenthAlpha(const UChar* string, const int length)
4298{
4299    // "0.X"
4300    if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
4301        return true;
4302
4303    // ".X"
4304    if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
4305        return true;
4306
4307    return false;
4308}
4309
4310static inline bool parseAlphaValue(const UChar*& string, const UChar* end, const char terminator, int& value)
4311{
4312    while (string != end && isHTMLSpace(*string))
4313        string++;
4314
4315    bool negative = false;
4316
4317    if (string != end && *string == '-') {
4318        negative = true;
4319        string++;
4320    }
4321
4322    value = 0;
4323
4324    int length = end - string;
4325    if (length < 2)
4326        return false;
4327
4328    if (string[length - 1] != terminator)
4329        return false;
4330
4331    if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
4332        if (checkForValidDouble(string, end, terminator)) {
4333            value = negative ? 0 : 255;
4334            string = end;
4335            return true;
4336        }
4337        return false;
4338    }
4339
4340    if (length == 2 && string[0] != '.') {
4341        value = !negative && string[0] == '1' ? 255 : 0;
4342        string = end;
4343        return true;
4344    }
4345
4346    if (isTenthAlpha(string, length - 1)) {
4347        static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
4348        value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
4349        string = end;
4350        return true;
4351    }
4352
4353    double alpha = 0;
4354    if (!parseDouble(string, end, terminator, alpha))
4355        return false;
4356    value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
4357    string = end;
4358    return true;
4359}
4360
4361static inline bool mightBeRGBA(const UChar* characters, unsigned length)
4362{
4363    if (length < 5)
4364        return false;
4365    return characters[4] == '('
4366        && (characters[0] | 0x20) == 'r'
4367        && (characters[1] | 0x20) == 'g'
4368        && (characters[2] | 0x20) == 'b'
4369        && (characters[3] | 0x20) == 'a';
4370}
4371
4372static inline bool mightBeRGB(const UChar* characters, unsigned length)
4373{
4374    if (length < 4)
4375        return false;
4376    return characters[3] == '('
4377        && (characters[0] | 0x20) == 'r'
4378        && (characters[1] | 0x20) == 'g'
4379        && (characters[2] | 0x20) == 'b';
4380}
4381
4382bool CSSParser::parseColor(const String &name, RGBA32& rgb, bool strict)
4383{
4384    const UChar* characters = name.characters();
4385    unsigned length = name.length();
4386    CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
4387
4388    if (!strict && length >= 3) {
4389        if (name[0] == '#') {
4390            if (Color::parseHexColor(characters + 1, length - 1, rgb))
4391                return true;
4392        } else {
4393            if (Color::parseHexColor(characters, length, rgb))
4394                return true;
4395        }
4396    }
4397
4398    // Try rgba() syntax.
4399    if (mightBeRGBA(characters, length)) {
4400        const UChar* current = characters + 5;
4401        const UChar* end = characters + length;
4402        int red;
4403        int green;
4404        int blue;
4405        int alpha;
4406
4407        if (!parseColorIntOrPercentage(current, end, ',', expect, red))
4408            return false;
4409        if (!parseColorIntOrPercentage(current, end, ',', expect, green))
4410            return false;
4411        if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
4412            return false;
4413        if (!parseAlphaValue(current, end, ')', alpha))
4414            return false;
4415        if (current != end)
4416            return false;
4417        rgb = makeRGBA(red, green, blue, alpha);
4418        return true;
4419    }
4420
4421    // Try rgb() syntax.
4422    if (mightBeRGB(characters, length)) {
4423        const UChar* current = characters + 4;
4424        const UChar* end = characters + length;
4425        int red;
4426        int green;
4427        int blue;
4428        if (!parseColorIntOrPercentage(current, end, ',', expect, red))
4429            return false;
4430        if (!parseColorIntOrPercentage(current, end, ',', expect, green))
4431            return false;
4432        if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
4433            return false;
4434        if (current != end)
4435            return false;
4436        rgb = makeRGB(red, green, blue);
4437        return true;
4438    }
4439
4440    // Try named colors.
4441    Color tc;
4442    tc.setNamedColor(name);
4443    if (tc.isValid()) {
4444        rgb = tc.rgb();
4445        return true;
4446    }
4447    return false;
4448}
4449
4450static inline int colorIntFromValue(CSSParserValue* v)
4451{
4452    if (v->fValue <= 0.0)
4453        return 0;
4454
4455    if (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE) {
4456        if (v->fValue >= 100.0)
4457            return 255;
4458        return static_cast<int>(v->fValue * 256.0 / 100.0);
4459    }
4460
4461    if (v->fValue >= 255.0)
4462        return 255;
4463
4464    return static_cast<int>(v->fValue);
4465}
4466
4467bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
4468{
4469    CSSParserValueList* args = value->function->args.get();
4470    CSSParserValue* v = args->current();
4471    Units unitType = FUnknown;
4472    // Get the first value and its type
4473    if (validUnit(v, FInteger, true))
4474        unitType = FInteger;
4475    else if (validUnit(v, FPercent, true))
4476        unitType = FPercent;
4477    else
4478        return false;
4479    colorArray[0] = colorIntFromValue(v);
4480    for (int i = 1; i < 3; i++) {
4481        v = args->next();
4482        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
4483            return false;
4484        v = args->next();
4485        if (!validUnit(v, unitType, true))
4486            return false;
4487        colorArray[i] = colorIntFromValue(v);
4488    }
4489    if (parseAlpha) {
4490        v = args->next();
4491        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
4492            return false;
4493        v = args->next();
4494        if (!validUnit(v, FNumber, true))
4495            return false;
4496        // Convert the floating pointer number of alpha to an integer in the range [0, 256),
4497        // with an equal distribution across all 256 values.
4498        colorArray[3] = static_cast<int>(max(0.0, min(1.0, v->fValue)) * nextafter(256.0, 0.0));
4499    }
4500    return true;
4501}
4502
4503// The CSS3 specification defines the format of a HSL color as
4504// hsl(<number>, <percent>, <percent>)
4505// and with alpha, the format is
4506// hsla(<number>, <percent>, <percent>, <number>)
4507// The first value, HUE, is in an angle with a value between 0 and 360
4508bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
4509{
4510    CSSParserValueList* args = value->function->args.get();
4511    CSSParserValue* v = args->current();
4512    // Get the first value
4513    if (!validUnit(v, FNumber, true))
4514        return false;
4515    // normalize the Hue value and change it to be between 0 and 1.0
4516    colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
4517    for (int i = 1; i < 3; i++) {
4518        v = args->next();
4519        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
4520            return false;
4521        v = args->next();
4522        if (!validUnit(v, FPercent, true))
4523            return false;
4524        colorArray[i] = max(0.0, min(100.0, v->fValue)) / 100.0; // needs to be value between 0 and 1.0
4525    }
4526    if (parseAlpha) {
4527        v = args->next();
4528        if (v->unit != CSSParserValue::Operator && v->iValue != ',')
4529            return false;
4530        v = args->next();
4531        if (!validUnit(v, FNumber, true))
4532            return false;
4533        colorArray[3] = max(0.0, min(1.0, v->fValue));
4534    }
4535    return true;
4536}
4537
4538PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value)
4539{
4540    RGBA32 c = Color::transparent;
4541    if (!parseColorFromValue(value ? value : m_valueList->current(), c))
4542        return 0;
4543    return primitiveValueCache()->createColorValue(c);
4544}
4545
4546bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
4547{
4548    if (!m_strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
4549        value->fValue >= 0. && value->fValue < 1000000.) {
4550        String str = String::format("%06d", (int)(value->fValue+.5));
4551        if (!CSSParser::parseColor(str, c, m_strict))
4552            return false;
4553    } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
4554                value->unit == CSSPrimitiveValue::CSS_IDENT ||
4555                (!m_strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
4556        if (!CSSParser::parseColor(value->string, c, m_strict && value->unit == CSSPrimitiveValue::CSS_IDENT))
4557            return false;
4558    } else if (value->unit == CSSParserValue::Function &&
4559                value->function->args != 0 &&
4560                value->function->args->size() == 5 /* rgb + two commas */ &&
4561                equalIgnoringCase(value->function->name, "rgb(")) {
4562        int colorValues[3];
4563        if (!parseColorParameters(value, colorValues, false))
4564            return false;
4565        c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
4566    } else {
4567        if (value->unit == CSSParserValue::Function &&
4568                value->function->args != 0 &&
4569                value->function->args->size() == 7 /* rgba + three commas */ &&
4570                equalIgnoringCase(value->function->name, "rgba(")) {
4571            int colorValues[4];
4572            if (!parseColorParameters(value, colorValues, true))
4573                return false;
4574            c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
4575        } else if (value->unit == CSSParserValue::Function &&
4576                    value->function->args != 0 &&
4577                    value->function->args->size() == 5 /* hsl + two commas */ &&
4578                    equalIgnoringCase(value->function->name, "hsl(")) {
4579            double colorValues[3];
4580            if (!parseHSLParameters(value, colorValues, false))
4581                return false;
4582            c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
4583        } else if (value->unit == CSSParserValue::Function &&
4584                    value->function->args != 0 &&
4585                    value->function->args->size() == 7 /* hsla + three commas */ &&
4586                    equalIgnoringCase(value->function->name, "hsla(")) {
4587            double colorValues[4];
4588            if (!parseHSLParameters(value, colorValues, true))
4589                return false;
4590            c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
4591        } else
4592            return false;
4593    }
4594
4595    return true;
4596}
4597
4598// This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
4599// without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
4600struct ShadowParseContext {
4601    ShadowParseContext(CSSPropertyID prop, CSSPrimitiveValueCache* primitiveValueCache)
4602        : property(prop)
4603        , m_primitiveValueCache(primitiveValueCache)
4604        , allowX(true)
4605        , allowY(false)
4606        , allowBlur(false)
4607        , allowSpread(false)
4608        , allowColor(true)
4609        , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
4610        , allowBreak(true)
4611    {
4612    }
4613
4614    bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
4615
4616    void commitValue()
4617    {
4618        // Handle the ,, case gracefully by doing nothing.
4619        if (x || y || blur || spread || color || style) {
4620            if (!values)
4621                values = CSSValueList::createCommaSeparated();
4622
4623            // Construct the current shadow value and add it to the list.
4624            values->append(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
4625        }
4626
4627        // Now reset for the next shadow value.
4628        x = 0;
4629        y = 0;
4630        blur = 0;
4631        spread = 0;
4632        style = 0;
4633        color = 0;
4634
4635        allowX = true;
4636        allowColor = true;
4637        allowBreak = true;
4638        allowY = false;
4639        allowBlur = false;
4640        allowSpread = false;
4641        allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
4642    }
4643
4644    void commitLength(CSSParserValue* v)
4645    {
4646        RefPtr<CSSPrimitiveValue> val = m_primitiveValueCache->createValue(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit);
4647
4648        if (allowX) {
4649            x = val.release();
4650            allowX = false;
4651            allowY = true;
4652            allowColor = false;
4653            allowStyle = false;
4654            allowBreak = false;
4655        } else if (allowY) {
4656            y = val.release();
4657            allowY = false;
4658            allowBlur = true;
4659            allowColor = true;
4660            allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
4661            allowBreak = true;
4662        } else if (allowBlur) {
4663            blur = val.release();
4664            allowBlur = false;
4665            allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
4666        } else if (allowSpread) {
4667            spread = val.release();
4668            allowSpread = false;
4669        }
4670    }
4671
4672    void commitColor(PassRefPtr<CSSPrimitiveValue> val)
4673    {
4674        color = val;
4675        allowColor = false;
4676        if (allowX) {
4677            allowStyle = false;
4678            allowBreak = false;
4679        } else {
4680            allowBlur = false;
4681            allowSpread = false;
4682            allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
4683        }
4684    }
4685
4686    void commitStyle(CSSParserValue* v)
4687    {
4688        style = m_primitiveValueCache->createIdentifierValue(v->id);
4689        allowStyle = false;
4690        if (allowX)
4691            allowBreak = false;
4692        else {
4693            allowBlur = false;
4694            allowSpread = false;
4695            allowColor = false;
4696        }
4697    }
4698
4699    CSSPropertyID property;
4700    CSSPrimitiveValueCache* m_primitiveValueCache;
4701
4702    RefPtr<CSSValueList> values;
4703    RefPtr<CSSPrimitiveValue> x;
4704    RefPtr<CSSPrimitiveValue> y;
4705    RefPtr<CSSPrimitiveValue> blur;
4706    RefPtr<CSSPrimitiveValue> spread;
4707    RefPtr<CSSPrimitiveValue> style;
4708    RefPtr<CSSPrimitiveValue> color;
4709
4710    bool allowX;
4711    bool allowY;
4712    bool allowBlur;
4713    bool allowSpread;
4714    bool allowColor;
4715    bool allowStyle; // inset or not.
4716    bool allowBreak;
4717};
4718
4719bool CSSParser::parseShadow(int propId, bool important)
4720{
4721    ShadowParseContext context(static_cast<CSSPropertyID>(propId), primitiveValueCache());
4722    CSSParserValue* val;
4723    while ((val = m_valueList->current())) {
4724        // Check for a comma break first.
4725        if (val->unit == CSSParserValue::Operator) {
4726            if (val->iValue != ',' || !context.allowBreak)
4727                // Other operators aren't legal or we aren't done with the current shadow
4728                // value.  Treat as invalid.
4729                return false;
4730#if ENABLE(SVG)
4731            // -webkit-svg-shadow does not support multiple values.
4732            if (static_cast<CSSPropertyID>(propId) == CSSPropertyWebkitSvgShadow)
4733                return false;
4734#endif
4735            // The value is good.  Commit it.
4736            context.commitValue();
4737        } else if (validUnit(val, FLength, true)) {
4738            // We required a length and didn't get one. Invalid.
4739            if (!context.allowLength())
4740                return false;
4741
4742            // A length is allowed here.  Construct the value and add it.
4743            context.commitLength(val);
4744        } else if (val->id == CSSValueInset) {
4745            if (!context.allowStyle)
4746                return false;
4747
4748            context.commitStyle(val);
4749        } else {
4750            // The only other type of value that's ok is a color value.
4751            RefPtr<CSSPrimitiveValue> parsedColor;
4752            bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu ||
4753                            (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && !m_strict));
4754            if (isColor) {
4755                if (!context.allowColor)
4756                    return false;
4757                parsedColor = primitiveValueCache()->createIdentifierValue(val->id);
4758            }
4759
4760            if (!parsedColor)
4761                // It's not built-in. Try to parse it as a color.
4762                parsedColor = parseColor(val);
4763
4764            if (!parsedColor || !context.allowColor)
4765                return false; // This value is not a color or length and is invalid or
4766                              // it is a color, but a color isn't allowed at this point.
4767
4768            context.commitColor(parsedColor.release());
4769        }
4770
4771        m_valueList->next();
4772    }
4773
4774    if (context.allowBreak) {
4775        context.commitValue();
4776        if (context.values->length()) {
4777            addProperty(propId, context.values.release(), important);
4778            m_valueList->next();
4779            return true;
4780        }
4781    }
4782
4783    return false;
4784}
4785
4786bool CSSParser::parseReflect(int propId, bool important)
4787{
4788    // box-reflect: <direction> <offset> <mask>
4789
4790    // Direction comes first.
4791    CSSParserValue* val = m_valueList->current();
4792    CSSReflectionDirection direction;
4793    switch (val->id) {
4794        case CSSValueAbove:
4795            direction = ReflectionAbove;
4796            break;
4797        case CSSValueBelow:
4798            direction = ReflectionBelow;
4799            break;
4800        case CSSValueLeft:
4801            direction = ReflectionLeft;
4802            break;
4803        case CSSValueRight:
4804            direction = ReflectionRight;
4805            break;
4806        default:
4807            return false;
4808    }
4809
4810    // The offset comes next.
4811    val = m_valueList->next();
4812    RefPtr<CSSPrimitiveValue> offset;
4813    if (!val)
4814        offset = primitiveValueCache()->createValue(0, CSSPrimitiveValue::CSS_PX);
4815    else {
4816        if (!validUnit(val, FLength | FPercent, m_strict))
4817            return false;
4818        offset = primitiveValueCache()->createValue(val->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(val->unit));
4819    }
4820
4821    // Now for the mask.
4822    RefPtr<CSSValue> mask;
4823    val = m_valueList->next();
4824    if (val) {
4825        if (!parseBorderImage(propId, important, mask))
4826            return false;
4827    }
4828
4829    RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction, offset.release(), mask.release());
4830    addProperty(propId, reflectValue.release(), important);
4831    m_valueList->next();
4832    return true;
4833}
4834
4835struct BorderImageParseContext {
4836    BorderImageParseContext(CSSPrimitiveValueCache* primitiveValueCache)
4837    : m_primitiveValueCache(primitiveValueCache)
4838    , m_allowBreak(false)
4839    , m_allowNumber(false)
4840    , m_allowSlash(false)
4841    , m_allowWidth(false)
4842    , m_allowRule(false)
4843    , m_borderTop(0)
4844    , m_borderRight(0)
4845    , m_borderBottom(0)
4846    , m_borderLeft(0)
4847    , m_horizontalRule(0)
4848    , m_verticalRule(0)
4849    {}
4850
4851    bool allowBreak() const { return m_allowBreak; }
4852    bool allowNumber() const { return m_allowNumber; }
4853    bool allowSlash() const { return m_allowSlash; }
4854    bool allowWidth() const { return m_allowWidth; }
4855    bool allowRule() const { return m_allowRule; }
4856
4857    void commitImage(PassRefPtr<CSSValue> image) { m_image = image; m_allowNumber = true; }
4858    void commitNumber(CSSParserValue* v)
4859    {
4860        PassRefPtr<CSSPrimitiveValue> val = m_primitiveValueCache->createValue(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit);
4861        if (!m_top)
4862            m_top = val;
4863        else if (!m_right)
4864            m_right = val;
4865        else if (!m_bottom)
4866            m_bottom = val;
4867        else {
4868            ASSERT(!m_left);
4869            m_left = val;
4870        }
4871
4872        m_allowBreak = m_allowSlash = m_allowRule = true;
4873        m_allowNumber = !m_left;
4874    }
4875    void commitSlash() { m_allowBreak = m_allowSlash = m_allowNumber = false; m_allowWidth = true; }
4876    void commitWidth(CSSParserValue* val)
4877    {
4878        if (!m_borderTop)
4879            m_borderTop = val;
4880        else if (!m_borderRight)
4881            m_borderRight = val;
4882        else if (!m_borderBottom)
4883            m_borderBottom = val;
4884        else {
4885            ASSERT(!m_borderLeft);
4886            m_borderLeft = val;
4887        }
4888
4889        m_allowBreak = m_allowRule = true;
4890        m_allowWidth = !m_borderLeft;
4891    }
4892    void commitRule(int keyword)
4893    {
4894        if (!m_horizontalRule)
4895            m_horizontalRule = keyword;
4896        else if (!m_verticalRule)
4897            m_verticalRule = keyword;
4898        m_allowRule = !m_verticalRule;
4899    }
4900    PassRefPtr<CSSValue> commitBorderImage(CSSParser* p, bool important)
4901    {
4902        // We need to clone and repeat values for any omissions.
4903        if (!m_right) {
4904            m_right = m_primitiveValueCache->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
4905            m_bottom = m_primitiveValueCache->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
4906            m_left = m_primitiveValueCache->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
4907        }
4908        if (!m_bottom) {
4909            m_bottom = m_primitiveValueCache->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
4910            m_left = m_primitiveValueCache->createValue(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType());
4911        }
4912        if (!m_left)
4913             m_left = m_primitiveValueCache->createValue(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType());
4914
4915        // Now build a rect value to hold all four of our primitive values.
4916        RefPtr<Rect> rect = Rect::create();
4917        rect->setTop(m_top);
4918        rect->setRight(m_right);
4919        rect->setBottom(m_bottom);
4920        rect->setLeft(m_left);
4921
4922        // Fill in STRETCH as the default if it wasn't specified.
4923        if (!m_horizontalRule)
4924            m_horizontalRule = CSSValueStretch;
4925
4926        // The vertical rule should match the horizontal rule if unspecified.
4927        if (!m_verticalRule)
4928            m_verticalRule = m_horizontalRule;
4929
4930        // Now we have to deal with the border widths.  The best way to deal with these is to actually put these values into a value
4931        // list and then make our parsing machinery do the parsing.
4932        if (m_borderTop) {
4933            CSSParserValueList newList;
4934            newList.addValue(*m_borderTop);
4935            if (m_borderRight)
4936                newList.addValue(*m_borderRight);
4937            if (m_borderBottom)
4938                newList.addValue(*m_borderBottom);
4939            if (m_borderLeft)
4940                newList.addValue(*m_borderLeft);
4941            CSSParserValueList* oldList = p->m_valueList;
4942            p->m_valueList = &newList;
4943            p->parseValue(CSSPropertyBorderWidth, important);
4944            p->m_valueList = oldList;
4945        }
4946
4947        // Make our new border image value now.
4948        return CSSBorderImageValue::create(m_image, rect.release(), m_horizontalRule, m_verticalRule);
4949    }
4950
4951    CSSPrimitiveValueCache* m_primitiveValueCache;
4952
4953    bool m_allowBreak;
4954    bool m_allowNumber;
4955    bool m_allowSlash;
4956    bool m_allowWidth;
4957    bool m_allowRule;
4958
4959    RefPtr<CSSValue> m_image;
4960
4961    RefPtr<CSSPrimitiveValue> m_top;
4962    RefPtr<CSSPrimitiveValue> m_right;
4963    RefPtr<CSSPrimitiveValue> m_bottom;
4964    RefPtr<CSSPrimitiveValue> m_left;
4965
4966    CSSParserValue* m_borderTop;
4967    CSSParserValue* m_borderRight;
4968    CSSParserValue* m_borderBottom;
4969    CSSParserValue* m_borderLeft;
4970
4971    int m_horizontalRule;
4972    int m_verticalRule;
4973};
4974
4975bool CSSParser::parseBorderImage(int propId, bool important, RefPtr<CSSValue>& result)
4976{
4977    // Look for an image initially.  If the first value is not a URI, then we're done.
4978    BorderImageParseContext context(primitiveValueCache());
4979    CSSParserValue* val = m_valueList->current();
4980    if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
4981        // FIXME: The completeURL call should be done when using the CSSImageValue,
4982        // not when creating it.
4983        context.commitImage(CSSImageValue::create(m_styleSheet->completeURL(val->string)));
4984    } else if (isGeneratedImageValue(val)) {
4985        RefPtr<CSSValue> value;
4986        if (parseGeneratedImage(value))
4987            context.commitImage(value);
4988        else
4989            return false;
4990    } else
4991        return false;
4992
4993    while ((val = m_valueList->next())) {
4994        if (context.allowNumber() && validUnit(val, FInteger | FNonNeg | FPercent, true)) {
4995            context.commitNumber(val);
4996        } else if (propId == CSSPropertyWebkitBorderImage && context.allowSlash() && val->unit == CSSParserValue::Operator && val->iValue == '/') {
4997            context.commitSlash();
4998        } else if (context.allowWidth() &&
4999            (val->id == CSSValueThin || val->id == CSSValueMedium || val->id == CSSValueThick || validUnit(val, FLength, m_strict))) {
5000            context.commitWidth(val);
5001        } else if (context.allowRule() &&
5002            (val->id == CSSValueStretch || val->id == CSSValueRound || val->id == CSSValueRepeat)) {
5003            context.commitRule(val->id);
5004        } else {
5005            // Something invalid was encountered.
5006            return false;
5007        }
5008    }
5009
5010    if (context.allowNumber() && propId != CSSPropertyWebkitBorderImage) {
5011        // Allow the slices to be omitted for images that don't fit to a border.  We just set the slices to be 0.
5012        context.m_top = primitiveValueCache()->createValue(0, CSSPrimitiveValue::CSS_NUMBER);
5013        context.m_allowBreak = true;
5014    }
5015
5016    if (context.allowBreak()) {
5017        // Need to fully commit as a single value.
5018        result = context.commitBorderImage(this, important);
5019        return true;
5020    }
5021
5022    return false;
5023}
5024
5025static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4])
5026{
5027    if (radii[3])
5028        return;
5029    if (!radii[2]) {
5030        if (!radii[1])
5031            radii[1] = radii[0];
5032        radii[2] = radii[0];
5033    }
5034    radii[3] = radii[1];
5035}
5036
5037bool CSSParser::parseBorderRadius(int propId, bool important)
5038{
5039    unsigned num = m_valueList->size();
5040    if (num > 9)
5041        return false;
5042
5043    ShorthandScope scope(this, propId);
5044    RefPtr<CSSPrimitiveValue> radii[2][4];
5045
5046    unsigned indexAfterSlash = 0;
5047    for (unsigned i = 0; i < num; ++i) {
5048        CSSParserValue* value = m_valueList->valueAt(i);
5049        if (value->unit == CSSParserValue::Operator) {
5050            if (value->iValue != '/')
5051                return false;
5052
5053            if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
5054                return false;
5055
5056            indexAfterSlash = i + 1;
5057            completeBorderRadii(radii[0]);
5058            continue;
5059        }
5060
5061        if (i - indexAfterSlash >= 4)
5062            return false;
5063
5064        if (!validUnit(value, FLength | FPercent, m_strict))
5065            return false;
5066
5067        RefPtr<CSSPrimitiveValue> radius = primitiveValueCache()->createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
5068
5069        if (!indexAfterSlash) {
5070            radii[0][i] = radius;
5071
5072            // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
5073            if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
5074                indexAfterSlash = 1;
5075                completeBorderRadii(radii[0]);
5076            }
5077        } else
5078            radii[1][i - indexAfterSlash] = radius.release();
5079    }
5080
5081    if (!indexAfterSlash) {
5082        completeBorderRadii(radii[0]);
5083        for (unsigned i = 0; i < 4; ++i)
5084            radii[1][i] = radii[0][i];
5085    } else
5086        completeBorderRadii(radii[1]);
5087
5088    m_implicitShorthand = true;
5089    addProperty(CSSPropertyBorderTopLeftRadius, primitiveValueCache()->createValue(Pair::create(radii[0][0].release(), radii[1][0].release())), important);
5090    addProperty(CSSPropertyBorderTopRightRadius, primitiveValueCache()->createValue(Pair::create(radii[0][1].release(), radii[1][1].release())), important);
5091    addProperty(CSSPropertyBorderBottomRightRadius, primitiveValueCache()->createValue(Pair::create(radii[0][2].release(), radii[1][2].release())), important);
5092    addProperty(CSSPropertyBorderBottomLeftRadius, primitiveValueCache()->createValue(Pair::create(radii[0][3].release(), radii[1][3].release())), important);
5093    m_implicitShorthand = false;
5094    return true;
5095}
5096
5097bool CSSParser::parseCounter(int propId, int defaultValue, bool important)
5098{
5099    enum { ID, VAL } state = ID;
5100
5101    RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
5102    RefPtr<CSSPrimitiveValue> counterName;
5103
5104    while (true) {
5105        CSSParserValue* val = m_valueList->current();
5106        switch (state) {
5107            case ID:
5108                if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
5109                    counterName = primitiveValueCache()->createValue(val->string, CSSPrimitiveValue::CSS_STRING);
5110                    state = VAL;
5111                    m_valueList->next();
5112                    continue;
5113                }
5114                break;
5115            case VAL: {
5116                int i = defaultValue;
5117                if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
5118                    i = clampToInteger(val->fValue);
5119                    m_valueList->next();
5120                }
5121
5122                list->append(primitiveValueCache()->createValue(Pair::create(counterName.release(),
5123                    primitiveValueCache()->createValue(i, CSSPrimitiveValue::CSS_NUMBER))));
5124                state = ID;
5125                continue;
5126            }
5127        }
5128        break;
5129    }
5130
5131    if (list->length() > 0) {
5132        addProperty(propId, list.release(), important);
5133        return true;
5134    }
5135
5136    return false;
5137}
5138
5139// This should go away once we drop support for -webkit-gradient
5140static PassRefPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal, CSSPrimitiveValueCache* primitiveValueCache)
5141{
5142    RefPtr<CSSPrimitiveValue> result;
5143    if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
5144        if ((equalIgnoringCase(a->string, "left") && horizontal) ||
5145            (equalIgnoringCase(a->string, "top") && !horizontal))
5146            result = primitiveValueCache->createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
5147        else if ((equalIgnoringCase(a->string, "right") && horizontal) ||
5148                 (equalIgnoringCase(a->string, "bottom") && !horizontal))
5149            result = primitiveValueCache->createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
5150        else if (equalIgnoringCase(a->string, "center"))
5151            result = primitiveValueCache->createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
5152    } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
5153        result = primitiveValueCache->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit);
5154    return result;
5155}
5156
5157static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
5158{
5159    if (a->unit != CSSParserValue::Function)
5160        return false;
5161
5162    if (!equalIgnoringCase(a->function->name, "from(") &&
5163        !equalIgnoringCase(a->function->name, "to(") &&
5164        !equalIgnoringCase(a->function->name, "color-stop("))
5165        return false;
5166
5167    CSSParserValueList* args = a->function->args.get();
5168    if (!args)
5169        return false;
5170
5171    if (equalIgnoringCase(a->function->name, "from(") ||
5172        equalIgnoringCase(a->function->name, "to(")) {
5173        // The "from" and "to" stops expect 1 argument.
5174        if (args->size() != 1)
5175            return false;
5176
5177        if (equalIgnoringCase(a->function->name, "from("))
5178            stop.m_position = p->primitiveValueCache()->createValue(0, CSSPrimitiveValue::CSS_NUMBER);
5179        else
5180            stop.m_position = p->primitiveValueCache()->createValue(1, CSSPrimitiveValue::CSS_NUMBER);
5181
5182        int id = args->current()->id;
5183        if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
5184            stop.m_color = p->primitiveValueCache()->createIdentifierValue(id);
5185        else
5186            stop.m_color = p->parseColor(args->current());
5187        if (!stop.m_color)
5188            return false;
5189    }
5190
5191    // The "color-stop" function expects 3 arguments.
5192    if (equalIgnoringCase(a->function->name, "color-stop(")) {
5193        if (args->size() != 3)
5194            return false;
5195
5196        CSSParserValue* stopArg = args->current();
5197        if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
5198            stop.m_position = p->primitiveValueCache()->createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
5199        else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
5200            stop.m_position = p->primitiveValueCache()->createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
5201        else
5202            return false;
5203
5204        stopArg = args->next();
5205        if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
5206            return false;
5207
5208        stopArg = args->next();
5209        int id = stopArg->id;
5210        if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
5211            stop.m_color = p->primitiveValueCache()->createIdentifierValue(id);
5212        else
5213            stop.m_color = p->parseColor(stopArg);
5214        if (!stop.m_color)
5215            return false;
5216    }
5217
5218    return true;
5219}
5220
5221bool CSSParser::parseDeprecatedGradient(RefPtr<CSSValue>& gradient)
5222{
5223    // Walk the arguments.
5224    CSSParserValueList* args = m_valueList->current()->function->args.get();
5225    if (!args || args->size() == 0)
5226        return false;
5227
5228    // The first argument is the gradient type.  It is an identifier.
5229    CSSGradientType gradientType;
5230    CSSParserValue* a = args->current();
5231    if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
5232        return false;
5233    if (equalIgnoringCase(a->string, "linear"))
5234        gradientType = CSSLinearGradient;
5235    else if (equalIgnoringCase(a->string, "radial"))
5236        gradientType = CSSRadialGradient;
5237    else
5238        return false;
5239
5240    RefPtr<CSSGradientValue> result;
5241    switch (gradientType) {
5242        case CSSLinearGradient:
5243            result = CSSLinearGradientValue::create(NonRepeating, true);
5244            break;
5245        case CSSRadialGradient:
5246            result = CSSRadialGradientValue::create(NonRepeating, true);
5247            break;
5248    }
5249
5250    // Comma.
5251    a = args->next();
5252    if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
5253        return false;
5254
5255    // Next comes the starting point for the gradient as an x y pair.  There is no
5256    // comma between the x and the y values.
5257    // First X.  It can be left, right, number or percent.
5258    a = args->next();
5259    if (!a)
5260        return false;
5261    RefPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true, primitiveValueCache());
5262    if (!point)
5263        return false;
5264    result->setFirstX(point.release());
5265
5266    // First Y.  It can be top, bottom, number or percent.
5267    a = args->next();
5268    if (!a)
5269        return false;
5270    point = parseDeprecatedGradientPoint(a, false, primitiveValueCache());
5271    if (!point)
5272        return false;
5273    result->setFirstY(point.release());
5274
5275    // Comma after the first point.
5276    a = args->next();
5277    if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
5278        return false;
5279
5280    // For radial gradients only, we now expect a numeric radius.
5281    if (gradientType == CSSRadialGradient) {
5282        a = args->next();
5283        if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
5284            return false;
5285        static_cast<CSSRadialGradientValue*>(result.get())->setFirstRadius(primitiveValueCache()->createValue(a->fValue, CSSPrimitiveValue::CSS_NUMBER));
5286
5287        // Comma after the first radius.
5288        a = args->next();
5289        if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
5290            return false;
5291    }
5292
5293    // Next is the ending point for the gradient as an x, y pair.
5294    // Second X.  It can be left, right, number or percent.
5295    a = args->next();
5296    if (!a)
5297        return false;
5298    point = parseDeprecatedGradientPoint(a, true, primitiveValueCache());
5299    if (!point)
5300        return false;
5301    result->setSecondX(point.release());
5302
5303    // Second Y.  It can be top, bottom, number or percent.
5304    a = args->next();
5305    if (!a)
5306        return false;
5307    point = parseDeprecatedGradientPoint(a, false, primitiveValueCache());
5308    if (!point)
5309        return false;
5310    result->setSecondY(point.release());
5311
5312    // For radial gradients only, we now expect the second radius.
5313    if (gradientType == CSSRadialGradient) {
5314        // Comma after the second point.
5315        a = args->next();
5316        if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
5317            return false;
5318
5319        a = args->next();
5320        if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
5321            return false;
5322        static_cast<CSSRadialGradientValue*>(result.get())->setSecondRadius(primitiveValueCache()->createValue(a->fValue, CSSPrimitiveValue::CSS_NUMBER));
5323    }
5324
5325    // We now will accept any number of stops (0 or more).
5326    a = args->next();
5327    while (a) {
5328        // Look for the comma before the next stop.
5329        if (a->unit != CSSParserValue::Operator || a->iValue != ',')
5330            return false;
5331
5332        // Now examine the stop itself.
5333        a = args->next();
5334        if (!a)
5335            return false;
5336
5337        // The function name needs to be one of "from", "to", or "color-stop."
5338        CSSGradientColorStop stop;
5339        if (!parseDeprecatedGradientColorStop(this, a, stop))
5340            return false;
5341        result->addStop(stop);
5342
5343        // Advance
5344        a = args->next();
5345    }
5346
5347    gradient = result.release();
5348    return true;
5349}
5350
5351static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal, CSSPrimitiveValueCache* primitiveValueCache)
5352{
5353    if (a->unit != CSSPrimitiveValue::CSS_IDENT)
5354        return 0;
5355
5356    switch (a->id) {
5357        case CSSValueLeft:
5358        case CSSValueRight:
5359            isHorizontal = true;
5360            break;
5361        case CSSValueTop:
5362        case CSSValueBottom:
5363            isHorizontal = false;
5364            break;
5365        default:
5366            return 0;
5367    }
5368    return primitiveValueCache->createIdentifierValue(a->id);
5369}
5370
5371static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSParser* p, CSSParserValue* value)
5372{
5373    int id = value->id;
5374    if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
5375        return p->primitiveValueCache()->createIdentifierValue(id);
5376
5377    return p->parseColor(value);
5378}
5379
5380bool CSSParser::parseLinearGradient(RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
5381{
5382    RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating);
5383
5384    // Walk the arguments.
5385    CSSParserValueList* args = m_valueList->current()->function->args.get();
5386    if (!args || !args->size())
5387        return false;
5388
5389    CSSParserValue* a = args->current();
5390    if (!a)
5391        return false;
5392
5393    bool expectComma = false;
5394    // Look for angle.
5395    if (validUnit(a, FAngle, true)) {
5396        result->setAngle(primitiveValueCache()->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit));
5397
5398        a = args->next();
5399        expectComma = true;
5400    } else {
5401        // Look one or two optional keywords that indicate a side or corner.
5402        RefPtr<CSSPrimitiveValue> startX, startY;
5403
5404        RefPtr<CSSPrimitiveValue> location;
5405        bool isHorizontal = false;
5406        if ((location = valueFromSideKeyword(a, isHorizontal, primitiveValueCache()))) {
5407            if (isHorizontal)
5408                startX = location;
5409            else
5410                startY = location;
5411
5412            a = args->next();
5413            if (a) {
5414                if ((location = valueFromSideKeyword(a, isHorizontal, primitiveValueCache()))) {
5415                    if (isHorizontal) {
5416                        if (startX)
5417                            return false;
5418                        startX = location;
5419                    } else {
5420                        if (startY)
5421                            return false;
5422                        startY = location;
5423                    }
5424
5425                    a = args->next();
5426                }
5427            }
5428
5429            expectComma = true;
5430        }
5431
5432        if (!startX && !startY)
5433            startY = primitiveValueCache()->createIdentifierValue(CSSValueTop);
5434
5435        result->setFirstX(startX.release());
5436        result->setFirstY(startY.release());
5437    }
5438
5439    if (!parseGradientColorStops(args, result.get(), expectComma))
5440        return false;
5441
5442    Vector<CSSGradientColorStop>& stops = result->stops();
5443    if (stops.isEmpty())
5444        return false;
5445
5446    gradient = result.release();
5447    return true;
5448}
5449
5450bool CSSParser::parseRadialGradient(RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
5451{
5452    RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating);
5453
5454    // Walk the arguments.
5455    CSSParserValueList* args = m_valueList->current()->function->args.get();
5456    if (!args || !args->size())
5457        return false;
5458
5459    CSSParserValue* a = args->current();
5460    if (!a)
5461        return false;
5462
5463    bool expectComma = false;
5464
5465    // Optional background-position
5466    RefPtr<CSSValue> centerX;
5467    RefPtr<CSSValue> centerY;
5468    // parseFillPosition advances the args next pointer.
5469    parseFillPosition(args, centerX, centerY);
5470    a = args->current();
5471
5472    if (centerX || centerY) {
5473        // Comma
5474        if (a->unit != CSSParserValue::Operator || a->iValue != ',')
5475            return false;
5476
5477        a = args->next();
5478        if (!a)
5479            return false;
5480    }
5481
5482    ASSERT(!centerX || centerX->isPrimitiveValue());
5483    ASSERT(!centerY || centerY->isPrimitiveValue());
5484
5485    result->setFirstX(static_cast<CSSPrimitiveValue*>(centerX.get()));
5486    result->setSecondX(static_cast<CSSPrimitiveValue*>(centerX.get()));
5487    // CSS3 radial gradients always share the same start and end point.
5488    result->setFirstY(static_cast<CSSPrimitiveValue*>(centerY.get()));
5489    result->setSecondY(static_cast<CSSPrimitiveValue*>(centerY.get()));
5490
5491    RefPtr<CSSPrimitiveValue> shapeValue;
5492    RefPtr<CSSPrimitiveValue> sizeValue;
5493
5494    // Optional shape and/or size in any order.
5495    for (int i = 0; i < 2; ++i) {
5496        if (a->unit != CSSPrimitiveValue::CSS_IDENT)
5497            break;
5498
5499        bool foundValue = false;
5500        switch (a->id) {
5501        case CSSValueCircle:
5502        case CSSValueEllipse:
5503            shapeValue = primitiveValueCache()->createIdentifierValue(a->id);
5504            foundValue = true;
5505            break;
5506        case CSSValueClosestSide:
5507        case CSSValueClosestCorner:
5508        case CSSValueFarthestSide:
5509        case CSSValueFarthestCorner:
5510        case CSSValueContain:
5511        case CSSValueCover:
5512            sizeValue = primitiveValueCache()->createIdentifierValue(a->id);
5513            foundValue = true;
5514            break;
5515        }
5516
5517        if (foundValue) {
5518            a = args->next();
5519            if (!a)
5520                return false;
5521
5522            expectComma = true;
5523        }
5524    }
5525
5526    result->setShape(shapeValue);
5527    result->setSizingBehavior(sizeValue);
5528
5529    // Or, two lengths or percentages
5530    RefPtr<CSSPrimitiveValue> horizontalSize;
5531    RefPtr<CSSPrimitiveValue> verticalSize;
5532
5533    if (!shapeValue && !sizeValue) {
5534        if (validUnit(a, FLength | FPercent, m_strict)) {
5535            horizontalSize = primitiveValueCache()->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
5536            a = args->next();
5537            if (!a)
5538                return false;
5539
5540            expectComma = true;
5541        }
5542
5543        if (validUnit(a, FLength | FPercent, m_strict)) {
5544            verticalSize = primitiveValueCache()->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
5545
5546            a = args->next();
5547            if (!a)
5548                return false;
5549            expectComma = true;
5550        }
5551    }
5552
5553    // Must have neither or both.
5554    if (!horizontalSize != !verticalSize)
5555        return false;
5556
5557    result->setEndHorizontalSize(horizontalSize);
5558    result->setEndVerticalSize(verticalSize);
5559
5560    if (!parseGradientColorStops(args, result.get(), expectComma))
5561        return false;
5562
5563    gradient = result.release();
5564    return true;
5565}
5566
5567bool CSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
5568{
5569    CSSParserValue* a = valueList->current();
5570
5571    // Now look for color stops.
5572    while (a) {
5573        // Look for the comma before the next stop.
5574        if (expectComma) {
5575            if (a->unit != CSSParserValue::Operator || a->iValue != ',')
5576                return false;
5577
5578            a = valueList->next();
5579            if (!a)
5580                return false;
5581        }
5582
5583        // <color-stop> = <color> [ <percentage> | <length> ]?
5584        CSSGradientColorStop stop;
5585        stop.m_color = parseGradientColorOrKeyword(this, a);
5586        if (!stop.m_color)
5587            return false;
5588
5589        a = valueList->next();
5590        if (a) {
5591            if (validUnit(a, FLength | FPercent, m_strict)) {
5592                stop.m_position = primitiveValueCache()->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit);
5593                a = valueList->next();
5594            }
5595        }
5596
5597        gradient->addStop(stop);
5598        expectComma = true;
5599    }
5600
5601    // Must have 2 or more stops to be valid.
5602    return gradient->stops().size() > 1;
5603}
5604
5605bool CSSParser::isGeneratedImageValue(CSSParserValue* val) const
5606{
5607    if (val->unit != CSSParserValue::Function)
5608        return false;
5609
5610    return equalIgnoringCase(val->function->name, "-webkit-gradient(")
5611        || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
5612        || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
5613        || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
5614        || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
5615        || equalIgnoringCase(val->function->name, "-webkit-canvas(");
5616}
5617
5618bool CSSParser::parseGeneratedImage(RefPtr<CSSValue>& value)
5619{
5620    CSSParserValue* val = m_valueList->current();
5621
5622    if (val->unit != CSSParserValue::Function)
5623        return false;
5624
5625    if (equalIgnoringCase(val->function->name, "-webkit-gradient("))
5626        return parseDeprecatedGradient(value);
5627
5628    if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient("))
5629        return parseLinearGradient(value, NonRepeating);
5630
5631    if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient("))
5632        return parseLinearGradient(value, Repeating);
5633
5634    if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient("))
5635        return parseRadialGradient(value, NonRepeating);
5636
5637    if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient("))
5638        return parseRadialGradient(value, Repeating);
5639
5640    if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
5641        return parseCanvas(value);
5642
5643    return false;
5644}
5645
5646bool CSSParser::parseCanvas(RefPtr<CSSValue>& canvas)
5647{
5648    RefPtr<CSSCanvasValue> result = CSSCanvasValue::create();
5649
5650    // Walk the arguments.
5651    CSSParserValueList* args = m_valueList->current()->function->args.get();
5652    if (!args || args->size() != 1)
5653        return false;
5654
5655    // The first argument is the canvas name.  It is an identifier.
5656    CSSParserValue* a = args->current();
5657    if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
5658        return false;
5659    result->setName(a->string);
5660    canvas = result;
5661    return true;
5662}
5663
5664class TransformOperationInfo {
5665public:
5666    TransformOperationInfo(const CSSParserString& name)
5667    : m_type(WebKitCSSTransformValue::UnknownTransformOperation)
5668    , m_argCount(1)
5669    , m_allowSingleArgument(false)
5670    , m_unit(CSSParser::FUnknown)
5671    {
5672        if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "scalex(") || equalIgnoringCase(name, "scaley(") || equalIgnoringCase(name, "scalez(")) {
5673            m_unit = CSSParser::FNumber;
5674            if (equalIgnoringCase(name, "scale("))
5675                m_type = WebKitCSSTransformValue::ScaleTransformOperation;
5676            else if (equalIgnoringCase(name, "scalex("))
5677                m_type = WebKitCSSTransformValue::ScaleXTransformOperation;
5678            else if (equalIgnoringCase(name, "scaley("))
5679                m_type = WebKitCSSTransformValue::ScaleYTransformOperation;
5680            else
5681                m_type = WebKitCSSTransformValue::ScaleZTransformOperation;
5682        } else if (equalIgnoringCase(name, "scale3d(")) {
5683            m_type = WebKitCSSTransformValue::Scale3DTransformOperation;
5684            m_argCount = 5;
5685            m_unit = CSSParser::FNumber;
5686        } else if (equalIgnoringCase(name, "rotate(")) {
5687            m_type = WebKitCSSTransformValue::RotateTransformOperation;
5688            m_unit = CSSParser::FAngle;
5689        } else if (equalIgnoringCase(name, "rotatex(") ||
5690                   equalIgnoringCase(name, "rotatey(") ||
5691                   equalIgnoringCase(name, "rotatez(")) {
5692            m_unit = CSSParser::FAngle;
5693            if (equalIgnoringCase(name, "rotatex("))
5694                m_type = WebKitCSSTransformValue::RotateXTransformOperation;
5695            else if (equalIgnoringCase(name, "rotatey("))
5696                m_type = WebKitCSSTransformValue::RotateYTransformOperation;
5697            else
5698                m_type = WebKitCSSTransformValue::RotateZTransformOperation;
5699        } else if (equalIgnoringCase(name, "rotate3d(")) {
5700            m_type = WebKitCSSTransformValue::Rotate3DTransformOperation;
5701            m_argCount = 7;
5702            m_unit = CSSParser::FNumber;
5703        } else if (equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "skewx(") || equalIgnoringCase(name, "skewy(")) {
5704            m_unit = CSSParser::FAngle;
5705            if (equalIgnoringCase(name, "skew("))
5706                m_type = WebKitCSSTransformValue::SkewTransformOperation;
5707            else if (equalIgnoringCase(name, "skewx("))
5708                m_type = WebKitCSSTransformValue::SkewXTransformOperation;
5709            else
5710                m_type = WebKitCSSTransformValue::SkewYTransformOperation;
5711        } else if (equalIgnoringCase(name, "translate(") || equalIgnoringCase(name, "translatex(") || equalIgnoringCase(name, "translatey(") || equalIgnoringCase(name, "translatez(")) {
5712            m_unit = CSSParser::FLength | CSSParser::FPercent;
5713            if (equalIgnoringCase(name, "translate("))
5714                m_type = WebKitCSSTransformValue::TranslateTransformOperation;
5715            else if (equalIgnoringCase(name, "translatex("))
5716                m_type = WebKitCSSTransformValue::TranslateXTransformOperation;
5717            else if (equalIgnoringCase(name, "translatey("))
5718                m_type = WebKitCSSTransformValue::TranslateYTransformOperation;
5719            else
5720                m_type = WebKitCSSTransformValue::TranslateZTransformOperation;
5721        } else if (equalIgnoringCase(name, "translate3d(")) {
5722            m_type = WebKitCSSTransformValue::Translate3DTransformOperation;
5723            m_argCount = 5;
5724            m_unit = CSSParser::FLength | CSSParser::FPercent;
5725        } else if (equalIgnoringCase(name, "matrix(")) {
5726            m_type = WebKitCSSTransformValue::MatrixTransformOperation;
5727            m_argCount = 11;
5728            m_unit = CSSParser::FNumber;
5729        } else if (equalIgnoringCase(name, "matrix3d(")) {
5730            m_type = WebKitCSSTransformValue::Matrix3DTransformOperation;
5731            m_argCount = 31;
5732            m_unit = CSSParser::FNumber;
5733        } else if (equalIgnoringCase(name, "perspective(")) {
5734            m_type = WebKitCSSTransformValue::PerspectiveTransformOperation;
5735            m_unit = CSSParser::FNumber;
5736        }
5737
5738        if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "translate(")) {
5739            m_allowSingleArgument = true;
5740            m_argCount = 3;
5741        }
5742    }
5743
5744    WebKitCSSTransformValue::TransformOperationType type() const { return m_type; }
5745    unsigned argCount() const { return m_argCount; }
5746    CSSParser::Units unit() const { return m_unit; }
5747
5748    bool unknown() const { return m_type == WebKitCSSTransformValue::UnknownTransformOperation; }
5749    bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
5750
5751private:
5752    WebKitCSSTransformValue::TransformOperationType m_type;
5753    unsigned m_argCount;
5754    bool m_allowSingleArgument;
5755    CSSParser::Units m_unit;
5756};
5757
5758PassRefPtr<CSSValueList> CSSParser::parseTransform()
5759{
5760    if (!m_valueList)
5761        return 0;
5762
5763    // The transform is a list of functional primitives that specify transform operations.
5764    // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation.
5765    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
5766    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
5767        if (value->unit != CSSParserValue::Function || !value->function)
5768            return 0;
5769
5770        // Every primitive requires at least one argument.
5771        CSSParserValueList* args = value->function->args.get();
5772        if (!args)
5773            return 0;
5774
5775        // See if the specified primitive is one we understand.
5776        TransformOperationInfo info(value->function->name);
5777        if (info.unknown())
5778            return 0;
5779
5780        if (!info.hasCorrectArgCount(args->size()))
5781            return 0;
5782
5783        // Create the new WebKitCSSTransformValue for this operation and add it to our list.
5784        RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(info.type());
5785        list->append(transformValue);
5786
5787        // Snag our values.
5788        CSSParserValue* a = args->current();
5789        unsigned argNumber = 0;
5790        while (a) {
5791            CSSParser::Units unit = info.unit();
5792
5793            if (info.type() == WebKitCSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
5794                // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
5795                if (!validUnit(a, FAngle, true))
5796                    return 0;
5797            } else if (info.type() == WebKitCSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
5798                // 3rd param of translate3d() cannot be a percentage
5799                if (!validUnit(a, FLength, true))
5800                    return 0;
5801            } else if (info.type() == WebKitCSSTransformValue::TranslateZTransformOperation && argNumber == 0) {
5802                // 1st param of translateZ() cannot be a percentage
5803                if (!validUnit(a, FLength, true))
5804                    return 0;
5805            } else if (info.type() == WebKitCSSTransformValue::PerspectiveTransformOperation && argNumber == 0) {
5806                // 1st param of perspective() must be a non-negative number (deprecated) or length.
5807                if (!validUnit(a, FNumber | FLength | FNonNeg, true))
5808                    return 0;
5809            } else if (!validUnit(a, unit, true))
5810                return 0;
5811
5812            // Add the value to the current transform operation.
5813            transformValue->append(primitiveValueCache()->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit));
5814
5815            a = args->next();
5816            if (!a)
5817                break;
5818            if (a->unit != CSSParserValue::Operator || a->iValue != ',')
5819                return 0;
5820            a = args->next();
5821
5822            argNumber++;
5823        }
5824    }
5825
5826    return list.release();
5827}
5828
5829bool CSSParser::parseTransformOrigin(int propId, int& propId1, int& propId2, int& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
5830{
5831    propId1 = propId;
5832    propId2 = propId;
5833    propId3 = propId;
5834    if (propId == CSSPropertyWebkitTransformOrigin) {
5835        propId1 = CSSPropertyWebkitTransformOriginX;
5836        propId2 = CSSPropertyWebkitTransformOriginY;
5837        propId3 = CSSPropertyWebkitTransformOriginZ;
5838    }
5839
5840    switch (propId) {
5841        case CSSPropertyWebkitTransformOrigin:
5842            if (!parseTransformOriginShorthand(value, value2, value3))
5843                return false;
5844            // parseTransformOriginShorthand advances the m_valueList pointer
5845            break;
5846        case CSSPropertyWebkitTransformOriginX: {
5847            value = parseFillPositionX(m_valueList);
5848            if (value)
5849                m_valueList->next();
5850            break;
5851        }
5852        case CSSPropertyWebkitTransformOriginY: {
5853            value = parseFillPositionY(m_valueList);
5854            if (value)
5855                m_valueList->next();
5856            break;
5857        }
5858        case CSSPropertyWebkitTransformOriginZ: {
5859            if (validUnit(m_valueList->current(), FLength, m_strict))
5860                value = primitiveValueCache()->createValue(m_valueList->current()->fValue, (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit);
5861            if (value)
5862                m_valueList->next();
5863            break;
5864        }
5865    }
5866
5867    return value;
5868}
5869
5870bool CSSParser::parsePerspectiveOrigin(int propId, int& propId1, int& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2)
5871{
5872    propId1 = propId;
5873    propId2 = propId;
5874    if (propId == CSSPropertyWebkitPerspectiveOrigin) {
5875        propId1 = CSSPropertyWebkitPerspectiveOriginX;
5876        propId2 = CSSPropertyWebkitPerspectiveOriginY;
5877    }
5878
5879    switch (propId) {
5880        case CSSPropertyWebkitPerspectiveOrigin:
5881            parseFillPosition(m_valueList, value, value2);
5882            break;
5883        case CSSPropertyWebkitPerspectiveOriginX: {
5884            value = parseFillPositionX(m_valueList);
5885            if (value)
5886                m_valueList->next();
5887            break;
5888        }
5889        case CSSPropertyWebkitPerspectiveOriginY: {
5890            value = parseFillPositionY(m_valueList);
5891            if (value)
5892                m_valueList->next();
5893            break;
5894        }
5895    }
5896
5897    return value;
5898}
5899
5900bool CSSParser::parseTextEmphasisStyle(bool important)
5901{
5902    unsigned valueListSize = m_valueList->size();
5903
5904    RefPtr<CSSPrimitiveValue> fill;
5905    RefPtr<CSSPrimitiveValue> shape;
5906
5907    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
5908        if (value->unit == CSSPrimitiveValue::CSS_STRING) {
5909            if (fill || shape || (valueListSize != 1 && !inShorthand()))
5910                return false;
5911            addProperty(CSSPropertyWebkitTextEmphasisStyle, primitiveValueCache()->createValue(value->string, CSSPrimitiveValue::CSS_STRING), important);
5912            m_valueList->next();
5913            return true;
5914        }
5915
5916        if (value->id == CSSValueNone) {
5917            if (fill || shape || (valueListSize != 1 && !inShorthand()))
5918                return false;
5919            addProperty(CSSPropertyWebkitTextEmphasisStyle, primitiveValueCache()->createIdentifierValue(CSSValueNone), important);
5920            m_valueList->next();
5921            return true;
5922        }
5923
5924        if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
5925            if (fill)
5926                return false;
5927            fill = primitiveValueCache()->createIdentifierValue(value->id);
5928        } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
5929            if (shape)
5930                return false;
5931            shape = primitiveValueCache()->createIdentifierValue(value->id);
5932        } else if (!inShorthand())
5933            return false;
5934        else
5935            break;
5936    }
5937
5938    if (fill && shape) {
5939        RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
5940        parsedValues->append(fill.release());
5941        parsedValues->append(shape.release());
5942        addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
5943        return true;
5944    }
5945    if (fill) {
5946        addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
5947        return true;
5948    }
5949    if (shape) {
5950        addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
5951        return true;
5952    }
5953
5954    return false;
5955}
5956
5957bool CSSParser::parseLineBoxContain(bool important)
5958{
5959    LineBoxContain lineBoxContain = LineBoxContainNone;
5960
5961    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
5962        if (value->id == CSSValueBlock) {
5963            if (lineBoxContain & LineBoxContainBlock)
5964                return false;
5965            lineBoxContain |= LineBoxContainBlock;
5966        } else if (value->id == CSSValueInline) {
5967            if (lineBoxContain & LineBoxContainInline)
5968                return false;
5969            lineBoxContain |= LineBoxContainInline;
5970        } else if (value->id == CSSValueFont) {
5971            if (lineBoxContain & LineBoxContainFont)
5972                return false;
5973            lineBoxContain |= LineBoxContainFont;
5974        } else if (value->id == CSSValueGlyphs) {
5975            if (lineBoxContain & LineBoxContainGlyphs)
5976                return false;
5977            lineBoxContain |= LineBoxContainGlyphs;
5978        } else if (value->id == CSSValueReplaced) {
5979            if (lineBoxContain & LineBoxContainReplaced)
5980                return false;
5981            lineBoxContain |= LineBoxContainReplaced;
5982        } else if (value->id == CSSValueInlineBox) {
5983            if (lineBoxContain & LineBoxContainInlineBox)
5984                return false;
5985            lineBoxContain |= LineBoxContainInlineBox;
5986        } else
5987            return false;
5988    }
5989
5990    if (!lineBoxContain)
5991        return false;
5992
5993    addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
5994    return true;
5995}
5996
5997static inline int yyerror(const char*) { return 1; }
5998
5999#define END_TOKEN 0
6000
6001#include "CSSGrammar.h"
6002
6003int CSSParser::lex(void* yylvalWithoutType)
6004{
6005    YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType);
6006    int length;
6007
6008    lex();
6009
6010    UChar* t = text(&length);
6011
6012    switch (token()) {
6013    case WHITESPACE:
6014    case SGML_CD:
6015    case INCLUDES:
6016    case DASHMATCH:
6017        break;
6018
6019    case URI:
6020    case STRING:
6021    case IDENT:
6022    case NTH:
6023    case HEX:
6024    case IDSEL:
6025    case DIMEN:
6026    case UNICODERANGE:
6027    case FUNCTION:
6028    case ANYFUNCTION:
6029    case NOTFUNCTION:
6030        yylval->string.characters = t;
6031        yylval->string.length = length;
6032        break;
6033
6034    case IMPORT_SYM:
6035    case PAGE_SYM:
6036    case MEDIA_SYM:
6037    case FONT_FACE_SYM:
6038    case CHARSET_SYM:
6039    case NAMESPACE_SYM:
6040    case WEBKIT_KEYFRAMES_SYM:
6041
6042    case IMPORTANT_SYM:
6043        break;
6044
6045    case QEMS:
6046        length--;
6047    case GRADS:
6048    case TURNS:
6049        length--;
6050    case DEGS:
6051    case RADS:
6052    case KHERTZ:
6053    case REMS:
6054        length--;
6055    case MSECS:
6056    case HERTZ:
6057    case EMS:
6058    case EXS:
6059    case PXS:
6060    case CMS:
6061    case MMS:
6062    case INS:
6063    case PTS:
6064    case PCS:
6065        length--;
6066    case SECS:
6067    case PERCENTAGE:
6068        length--;
6069    case FLOATTOKEN:
6070    case INTEGER:
6071        yylval->number = charactersToDouble(t, length);
6072        break;
6073
6074    default:
6075        break;
6076    }
6077
6078    return token();
6079}
6080
6081void CSSParser::recheckAtKeyword(const UChar* str, int len)
6082{
6083    String ruleName(str, len);
6084    if (equalIgnoringCase(ruleName, "@import"))
6085        yyTok = IMPORT_SYM;
6086    else if (equalIgnoringCase(ruleName, "@page"))
6087        yyTok = PAGE_SYM;
6088    else if (equalIgnoringCase(ruleName, "@media"))
6089        yyTok = MEDIA_SYM;
6090    else if (equalIgnoringCase(ruleName, "@font-face"))
6091        yyTok = FONT_FACE_SYM;
6092    else if (equalIgnoringCase(ruleName, "@charset"))
6093        yyTok = CHARSET_SYM;
6094    else if (equalIgnoringCase(ruleName, "@namespace"))
6095        yyTok = NAMESPACE_SYM;
6096    else if (equalIgnoringCase(ruleName, "@-webkit-keyframes"))
6097        yyTok = WEBKIT_KEYFRAMES_SYM;
6098    else if (equalIgnoringCase(ruleName, "@-webkit-mediaquery"))
6099        yyTok = WEBKIT_MEDIAQUERY_SYM;
6100}
6101
6102UChar* CSSParser::text(int *length)
6103{
6104    UChar* start = yytext;
6105    int l = yyleng;
6106    switch (yyTok) {
6107    case STRING:
6108        l--;
6109        /* nobreak */
6110    case HEX:
6111    case IDSEL:
6112        start++;
6113        l--;
6114        break;
6115    case URI:
6116        // "url("{w}{string}{w}")"
6117        // "url("{w}{url}{w}")"
6118        // strip "url(" and ")"
6119        start += 4;
6120        l -= 5;
6121        // strip {w}
6122        while (l && isHTMLSpace(*start)) {
6123            ++start;
6124            --l;
6125        }
6126        while (l && isHTMLSpace(start[l - 1]))
6127            --l;
6128        if (l && (*start == '"' || *start == '\'')) {
6129            ASSERT(l >= 2 && start[l - 1] == *start);
6130            ++start;
6131            l -= 2;
6132        }
6133        break;
6134    default:
6135        break;
6136    }
6137
6138    // process escapes
6139    UChar* out = start;
6140    UChar* escape = 0;
6141
6142    bool sawEscape = false;
6143
6144    for (int i = 0; i < l; i++) {
6145        UChar* current = start + i;
6146        if (escape == current - 1) {
6147            if (isASCIIHexDigit(*current))
6148                continue;
6149            if (yyTok == STRING &&
6150                 (*current == '\n' || *current == '\r' || *current == '\f')) {
6151                // ### handle \r\n case
6152                if (*current != '\r')
6153                    escape = 0;
6154                continue;
6155            }
6156            // in all other cases copy the char to output
6157            // ###
6158            *out++ = *current;
6159            escape = 0;
6160            continue;
6161        }
6162        if (escape == current - 2 && yyTok == STRING &&
6163             *(current-1) == '\r' && *current == '\n') {
6164            escape = 0;
6165            continue;
6166        }
6167        if (escape > current - 7 && isASCIIHexDigit(*current))
6168            continue;
6169        if (escape) {
6170            // add escaped char
6171            unsigned uc = 0;
6172            escape++;
6173            while (escape < current) {
6174                uc *= 16;
6175                uc += toASCIIHexValue(*escape);
6176                escape++;
6177            }
6178            // can't handle chars outside ucs2
6179            if (uc > 0xffff)
6180                uc = 0xfffd;
6181            *out++ = uc;
6182            escape = 0;
6183            if (isHTMLSpace(*current))
6184                continue;
6185        }
6186        if (!escape && *current == '\\') {
6187            escape = current;
6188            sawEscape = true;
6189            continue;
6190        }
6191        *out++ = *current;
6192    }
6193    if (escape) {
6194        // add escaped char
6195        unsigned uc = 0;
6196        escape++;
6197        while (escape < start+l) {
6198            uc *= 16;
6199            uc += toASCIIHexValue(*escape);
6200            escape++;
6201        }
6202        // can't handle chars outside ucs2
6203        if (uc > 0xffff)
6204            uc = 0xfffd;
6205        *out++ = uc;
6206    }
6207
6208    *length = out - start;
6209
6210    // If we have an unrecognized @-keyword, and if we handled any escapes at all, then
6211    // we should attempt to adjust yyTok to the correct type.
6212    if (yyTok == ATKEYWORD && sawEscape)
6213        recheckAtKeyword(start, *length);
6214
6215    return start;
6216}
6217
6218void CSSParser::countLines()
6219{
6220    for (UChar* current = yytext; current < yytext + yyleng; ++current) {
6221        if (*current == '\n')
6222            ++m_lineNumber;
6223    }
6224}
6225
6226CSSParserSelector* CSSParser::createFloatingSelector()
6227{
6228    CSSParserSelector* selector = new CSSParserSelector;
6229    m_floatingSelectors.add(selector);
6230    return selector;
6231}
6232
6233PassOwnPtr<CSSParserSelector> CSSParser::sinkFloatingSelector(CSSParserSelector* selector)
6234{
6235    if (selector) {
6236        ASSERT(m_floatingSelectors.contains(selector));
6237        m_floatingSelectors.remove(selector);
6238    }
6239    return adoptPtr(selector);
6240}
6241
6242Vector<OwnPtr<CSSParserSelector> >* CSSParser::createFloatingSelectorVector()
6243{
6244    Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >;
6245    m_floatingSelectorVectors.add(selectorVector);
6246    return selectorVector;
6247}
6248
6249PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > CSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector)
6250{
6251    if (selectorVector) {
6252        ASSERT(m_floatingSelectorVectors.contains(selectorVector));
6253        m_floatingSelectorVectors.remove(selectorVector);
6254    }
6255    return adoptPtr(selectorVector);
6256}
6257
6258CSSParserValueList* CSSParser::createFloatingValueList()
6259{
6260    CSSParserValueList* list = new CSSParserValueList;
6261    m_floatingValueLists.add(list);
6262    return list;
6263}
6264
6265CSSParserValueList* CSSParser::sinkFloatingValueList(CSSParserValueList* list)
6266{
6267    if (list) {
6268        ASSERT(m_floatingValueLists.contains(list));
6269        m_floatingValueLists.remove(list);
6270    }
6271    return list;
6272}
6273
6274CSSParserFunction* CSSParser::createFloatingFunction()
6275{
6276    CSSParserFunction* function = new CSSParserFunction;
6277    m_floatingFunctions.add(function);
6278    return function;
6279}
6280
6281CSSParserFunction* CSSParser::sinkFloatingFunction(CSSParserFunction* function)
6282{
6283    if (function) {
6284        ASSERT(m_floatingFunctions.contains(function));
6285        m_floatingFunctions.remove(function);
6286    }
6287    return function;
6288}
6289
6290CSSParserValue& CSSParser::sinkFloatingValue(CSSParserValue& value)
6291{
6292    if (value.unit == CSSParserValue::Function) {
6293        ASSERT(m_floatingFunctions.contains(value.function));
6294        m_floatingFunctions.remove(value.function);
6295    }
6296    return value;
6297}
6298
6299MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
6300{
6301    m_floatingMediaQueryExp = MediaQueryExp::create(mediaFeature, values);
6302    return m_floatingMediaQueryExp.get();
6303}
6304
6305PassOwnPtr<MediaQueryExp> CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression)
6306{
6307    ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp);
6308    return m_floatingMediaQueryExp.release();
6309}
6310
6311Vector<OwnPtr<MediaQueryExp> >* CSSParser::createFloatingMediaQueryExpList()
6312{
6313    m_floatingMediaQueryExpList = adoptPtr(new Vector<OwnPtr<MediaQueryExp> >);
6314    return m_floatingMediaQueryExpList.get();
6315}
6316
6317PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > CSSParser::sinkFloatingMediaQueryExpList(Vector<OwnPtr<MediaQueryExp> >* list)
6318{
6319    ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList);
6320    return m_floatingMediaQueryExpList.release();
6321}
6322
6323MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const String& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
6324{
6325    m_floatingMediaQuery = adoptPtr(new MediaQuery(restrictor, mediaType, expressions));
6326    return m_floatingMediaQuery.get();
6327}
6328
6329MediaQuery* CSSParser::createFloatingMediaQuery(PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
6330{
6331    return createFloatingMediaQuery(MediaQuery::None, "all", expressions);
6332}
6333
6334PassOwnPtr<MediaQuery> CSSParser::sinkFloatingMediaQuery(MediaQuery* query)
6335{
6336    ASSERT_UNUSED(query, query == m_floatingMediaQuery);
6337    return m_floatingMediaQuery.release();
6338}
6339
6340MediaList* CSSParser::createMediaList()
6341{
6342    RefPtr<MediaList> list = MediaList::create();
6343    MediaList* result = list.get();
6344    m_parsedStyleObjects.append(list.release());
6345    return result;
6346}
6347
6348CSSRule* CSSParser::createCharsetRule(const CSSParserString& charset)
6349{
6350    if (!m_styleSheet)
6351        return 0;
6352    RefPtr<CSSCharsetRule> rule = CSSCharsetRule::create(m_styleSheet, charset);
6353    CSSCharsetRule* result = rule.get();
6354    m_parsedStyleObjects.append(rule.release());
6355    return result;
6356}
6357
6358CSSRule* CSSParser::createImportRule(const CSSParserString& url, MediaList* media)
6359{
6360    if (!media || !m_styleSheet || !m_allowImportRules)
6361        return 0;
6362    RefPtr<CSSImportRule> rule = CSSImportRule::create(m_styleSheet, url, media);
6363    CSSImportRule* result = rule.get();
6364    m_parsedStyleObjects.append(rule.release());
6365    return result;
6366}
6367
6368CSSRule* CSSParser::createMediaRule(MediaList* media, CSSRuleList* rules)
6369{
6370    if (!media || !rules || !m_styleSheet)
6371        return 0;
6372    m_allowImportRules = m_allowNamespaceDeclarations = false;
6373    RefPtr<CSSMediaRule> rule = CSSMediaRule::create(m_styleSheet, media, rules);
6374    CSSMediaRule* result = rule.get();
6375    m_parsedStyleObjects.append(rule.release());
6376    return result;
6377}
6378
6379CSSRuleList* CSSParser::createRuleList()
6380{
6381    RefPtr<CSSRuleList> list = CSSRuleList::create();
6382    CSSRuleList* listPtr = list.get();
6383
6384    m_parsedRuleLists.append(list.release());
6385    return listPtr;
6386}
6387
6388WebKitCSSKeyframesRule* CSSParser::createKeyframesRule()
6389{
6390    m_allowImportRules = m_allowNamespaceDeclarations = false;
6391    RefPtr<WebKitCSSKeyframesRule> rule = WebKitCSSKeyframesRule::create(m_styleSheet);
6392    WebKitCSSKeyframesRule* rulePtr = rule.get();
6393    m_parsedStyleObjects.append(rule.release());
6394    return rulePtr;
6395}
6396
6397CSSRule* CSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors)
6398{
6399    CSSStyleRule* result = 0;
6400    markRuleBodyEnd();
6401    if (selectors) {
6402        m_allowImportRules = m_allowNamespaceDeclarations = false;
6403        RefPtr<CSSStyleRule> rule = CSSStyleRule::create(m_styleSheet, m_lastSelectorLineNumber);
6404        rule->adoptSelectorVector(*selectors);
6405        if (m_hasFontFaceOnlyValues)
6406            deleteFontFaceOnlyValues();
6407        rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties));
6408        result = rule.get();
6409        m_parsedStyleObjects.append(rule.release());
6410        if (m_ruleRangeMap) {
6411            ASSERT(m_currentRuleData);
6412            m_currentRuleData->styleSourceData->styleBodyRange = m_ruleBodyRange;
6413            m_currentRuleData->selectorListRange = m_selectorListRange;
6414            m_ruleRangeMap->set(result, m_currentRuleData.release());
6415            m_currentRuleData = CSSRuleSourceData::create();
6416            m_currentRuleData->styleSourceData = CSSStyleSourceData::create();
6417            m_inStyleRuleOrDeclaration = false;
6418        }
6419    }
6420    resetSelectorListMarks();
6421    resetRuleBodyMarks();
6422    clearProperties();
6423    return result;
6424}
6425
6426CSSRule* CSSParser::createFontFaceRule()
6427{
6428    m_allowImportRules = m_allowNamespaceDeclarations = false;
6429    for (unsigned i = 0; i < m_numParsedProperties; ++i) {
6430        CSSProperty* property = m_parsedProperties[i];
6431        int id = property->id();
6432        if ((id == CSSPropertyFontWeight || id == CSSPropertyFontStyle || id == CSSPropertyFontVariant) && property->value()->isPrimitiveValue()) {
6433            RefPtr<CSSValue> value = property->m_value.release();
6434            property->m_value = CSSValueList::createCommaSeparated();
6435            static_cast<CSSValueList*>(property->value())->append(value.release());
6436        } else if (id == CSSPropertyFontFamily && (!property->value()->isValueList() || static_cast<CSSValueList*>(property->value())->length() != 1)) {
6437            // Unlike font-family property, font-family descriptor in @font-face rule
6438            // has to be a value list with exactly one family name. It cannot have a
6439            // have 'initial' value and cannot 'inherit' from parent.
6440            // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
6441            clearProperties();
6442            return 0;
6443        }
6444    }
6445    RefPtr<CSSFontFaceRule> rule = CSSFontFaceRule::create(m_styleSheet);
6446    rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties));
6447    clearProperties();
6448    CSSFontFaceRule* result = rule.get();
6449    m_parsedStyleObjects.append(rule.release());
6450    return result;
6451}
6452
6453void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
6454{
6455    if (!m_styleSheet || !m_allowNamespaceDeclarations)
6456        return;
6457    m_allowImportRules = false;
6458    m_styleSheet->addNamespace(this, prefix, uri);
6459}
6460
6461void CSSParser::updateSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers)
6462{
6463    AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
6464    QualifiedName tag = QualifiedName(namespacePrefix, elementName, determinedNamespace);
6465    if (!specifiers->isUnknownPseudoElement()) {
6466        specifiers->setTag(tag);
6467        return;
6468    }
6469
6470    specifiers->setRelation(CSSSelector::ShadowDescendant);
6471    if (CSSParserSelector* history = specifiers->tagHistory()) {
6472        history->setTag(tag);
6473        return;
6474    }
6475
6476    // No need to create an extra element name selector if we are matching any element
6477    // in any namespace.
6478    if (elementName == starAtom && m_defaultNamespace == starAtom)
6479        return;
6480
6481    CSSParserSelector* elementNameSelector = new CSSParserSelector;
6482    elementNameSelector->setTag(tag);
6483    specifiers->setTagHistory(elementNameSelector);
6484}
6485
6486
6487CSSRule* CSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector)
6488{
6489    // FIXME: Margin at-rules are ignored.
6490    m_allowImportRules = m_allowNamespaceDeclarations = false;
6491    CSSPageRule* pageRule = 0;
6492    if (pageSelector) {
6493        RefPtr<CSSPageRule> rule = CSSPageRule::create(m_styleSheet, m_lastSelectorLineNumber);
6494        Vector<OwnPtr<CSSParserSelector> > selectorVector;
6495        selectorVector.append(pageSelector);
6496        rule->adoptSelectorVector(selectorVector);
6497        rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties));
6498        pageRule = rule.get();
6499        m_parsedStyleObjects.append(rule.release());
6500    }
6501    clearProperties();
6502    return pageRule;
6503}
6504
6505CSSRule* CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
6506{
6507    // FIXME: Implement margin at-rule here, using:
6508    //        - marginBox: margin box
6509    //        - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_numParsedProperties) are for this at-rule.
6510    // 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.
6511
6512    endDeclarationsForMarginBox();
6513    return 0; // until this method is implemented.
6514}
6515
6516void CSSParser::startDeclarationsForMarginBox()
6517{
6518    m_numParsedPropertiesBeforeMarginBox = m_numParsedProperties;
6519}
6520
6521void CSSParser::endDeclarationsForMarginBox()
6522{
6523    ASSERT(m_numParsedPropertiesBeforeMarginBox != INVALID_NUM_PARSED_PROPERTIES);
6524    rollbackLastProperties(m_numParsedProperties - m_numParsedPropertiesBeforeMarginBox);
6525    m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
6526}
6527
6528void CSSParser::deleteFontFaceOnlyValues()
6529{
6530    ASSERT(m_hasFontFaceOnlyValues);
6531    int deletedProperties = 0;
6532
6533    for (unsigned i = 0; i < m_numParsedProperties; ++i) {
6534        CSSProperty* property = m_parsedProperties[i];
6535        int id = property->id();
6536        if ((id == CSSPropertyFontWeight || id == CSSPropertyFontStyle || id == CSSPropertyFontVariant) && property->value()->isValueList()) {
6537            delete property;
6538            deletedProperties++;
6539        } else if (deletedProperties)
6540            m_parsedProperties[i - deletedProperties] = m_parsedProperties[i];
6541    }
6542
6543    m_numParsedProperties -= deletedProperties;
6544}
6545
6546WebKitCSSKeyframeRule* CSSParser::createKeyframeRule(CSSParserValueList* keys)
6547{
6548    // Create a key string from the passed keys
6549    String keyString;
6550    for (unsigned i = 0; i < keys->size(); ++i) {
6551        float key = (float) keys->valueAt(i)->fValue;
6552        if (i != 0)
6553            keyString += ",";
6554        keyString += String::number(key);
6555        keyString += "%";
6556    }
6557
6558    RefPtr<WebKitCSSKeyframeRule> keyframe = WebKitCSSKeyframeRule::create(m_styleSheet);
6559    keyframe->setKeyText(keyString);
6560    keyframe->setDeclaration(CSSMutableStyleDeclaration::create(0, m_parsedProperties, m_numParsedProperties));
6561
6562    clearProperties();
6563
6564    WebKitCSSKeyframeRule* keyframePtr = keyframe.get();
6565    m_parsedStyleObjects.append(keyframe.release());
6566    return keyframePtr;
6567}
6568
6569void CSSParser::invalidBlockHit()
6570{
6571    if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
6572        m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
6573}
6574
6575void CSSParser::updateLastSelectorLineAndPosition()
6576{
6577    m_lastSelectorLineNumber = m_lineNumber;
6578    markRuleBodyStart();
6579}
6580
6581void CSSParser::markSelectorListStart()
6582{
6583    m_selectorListRange.start = yytext - m_data;
6584}
6585
6586void CSSParser::markSelectorListEnd()
6587{
6588    if (!m_currentRuleData)
6589        return;
6590    UChar* listEnd = yytext;
6591    while (listEnd > m_data + 1) {
6592        if (isHTMLSpace(*(listEnd - 1)))
6593            --listEnd;
6594        else
6595            break;
6596    }
6597    m_selectorListRange.end = listEnd - m_data;
6598}
6599
6600void CSSParser::markRuleBodyStart()
6601{
6602    unsigned offset = yytext - m_data;
6603    if (*yytext == '{')
6604        ++offset; // Skip the rule body opening brace.
6605    if (offset > m_ruleBodyRange.start)
6606        m_ruleBodyRange.start = offset;
6607    m_inStyleRuleOrDeclaration = true;
6608}
6609
6610void CSSParser::markRuleBodyEnd()
6611{
6612    unsigned offset = yytext - m_data;
6613    if (offset > m_ruleBodyRange.end)
6614        m_ruleBodyRange.end = offset;
6615}
6616
6617void CSSParser::markPropertyStart()
6618{
6619    if (!m_inStyleRuleOrDeclaration)
6620        return;
6621    m_propertyRange.start = yytext - m_data;
6622}
6623
6624void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed)
6625{
6626    if (!m_inStyleRuleOrDeclaration)
6627        return;
6628    unsigned offset = yytext - m_data;
6629    if (*yytext == ';') // Include semicolon into the property text.
6630        ++offset;
6631    m_propertyRange.end = offset;
6632    if (m_propertyRange.start != UINT_MAX && m_currentRuleData) {
6633        // This stuff is only executed when the style data retrieval is requested by client.
6634        const unsigned start = m_propertyRange.start;
6635        const unsigned end = m_propertyRange.end;
6636        ASSERT(start < end);
6637        String propertyString = String(m_data + start, end - start).stripWhiteSpace();
6638        if (propertyString.endsWith(";", true))
6639            propertyString = propertyString.left(propertyString.length() - 1);
6640        Vector<String> propertyComponents;
6641        size_t colonIndex = propertyString.find(":");
6642        ASSERT(colonIndex != notFound);
6643
6644        String name = propertyString.left(colonIndex).stripWhiteSpace();
6645        String value = propertyString.substring(colonIndex + 1, propertyString.length()).stripWhiteSpace();
6646        // The property range is relative to the declaration start offset.
6647        m_currentRuleData->styleSourceData->propertyData.append(
6648            CSSPropertySourceData(name, value, isImportantFound, isPropertyParsed, SourceRange(start - m_ruleBodyRange.start, end - m_ruleBodyRange.start)));
6649    }
6650    resetPropertyMarks();
6651}
6652
6653static int cssPropertyID(const UChar* propertyName, unsigned length)
6654{
6655    if (!length)
6656        return 0;
6657    if (length > maxCSSPropertyNameLength)
6658        return 0;
6659
6660    char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
6661
6662    for (unsigned i = 0; i != length; ++i) {
6663        UChar c = propertyName[i];
6664        if (c == 0 || c >= 0x7F)
6665            return 0; // illegal character
6666        buffer[i] = toASCIILower(c);
6667    }
6668    buffer[length] = '\0';
6669
6670    const char* name = buffer;
6671    if (buffer[0] == '-') {
6672        // If the prefix is -apple- or -khtml-, change it to -webkit-.
6673        // This makes the string one character longer.
6674        if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
6675            memmove(buffer + 7, buffer + 6, length + 1 - 6);
6676            memcpy(buffer, "-webkit", 7);
6677            ++length;
6678        }
6679
6680        if (hasPrefix(buffer, length, "-webkit")) {
6681            if (!strcmp(buffer, "-webkit-box-sizing")) {
6682                // -webkit-box-sizing worked in Safari 4 and earlier.
6683                const char* const boxSizing = "box-sizing";
6684                name = boxSizing;
6685                length = strlen(boxSizing);
6686            } else if (!strcmp(buffer, "-webkit-opacity")) {
6687                // Honor -webkit-opacity as a synonym for opacity.
6688                // This was the only syntax that worked in Safari 1.1, and may be in use on some websites and widgets.
6689                const char* const opacity = "opacity";
6690                name = opacity;
6691                length = strlen(opacity);
6692#if PLATFORM(IOS)
6693            } else if (!strcmp(buffer, "-webkit-hyphenate-locale")) {
6694                // Worked in iOS 4.2.
6695                const char* const webkitLocale = "-webkit-locale";
6696                name = webkitLocale;
6697                length = strlen(webkitLocale);
6698#endif
6699            } else if (hasPrefix(buffer + 7, length - 7, "-border-")) {
6700                // -webkit-border-*-*-radius worked in Safari 4 and earlier. -webkit-border-radius syntax
6701                // differs from border-radius, so it is remains as a distinct property.
6702                if (!strcmp(buffer + 15, "top-left-radius")
6703                        || !strcmp(buffer + 15, "top-right-radius")
6704                        || !strcmp(buffer + 15, "bottom-right-radius")
6705                        || !strcmp(buffer + 15, "bottom-left-radius")) {
6706                    name = buffer + 8;
6707                    length -= 8;
6708                }
6709            }
6710        }
6711    }
6712
6713    const Property* hashTableEntry = findProperty(name, length);
6714    return hashTableEntry ? hashTableEntry->id : 0;
6715}
6716
6717int cssPropertyID(const String& string)
6718{
6719    return cssPropertyID(string.characters(), string.length());
6720}
6721
6722int cssPropertyID(const CSSParserString& string)
6723{
6724    return cssPropertyID(string.characters, string.length);
6725}
6726
6727int cssValueKeywordID(const CSSParserString& string)
6728{
6729    unsigned length = string.length;
6730    if (!length)
6731        return 0;
6732    if (length > maxCSSValueKeywordLength)
6733        return 0;
6734
6735    char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
6736
6737    for (unsigned i = 0; i != length; ++i) {
6738        UChar c = string.characters[i];
6739        if (c == 0 || c >= 0x7F)
6740            return 0; // illegal character
6741        buffer[i] = WTF::toASCIILower(c);
6742    }
6743    buffer[length] = '\0';
6744
6745    if (buffer[0] == '-') {
6746        // If the prefix is -apple- or -khtml-, change it to -webkit-.
6747        // This makes the string one character longer.
6748        if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
6749            memmove(buffer + 7, buffer + 6, length + 1 - 6);
6750            memcpy(buffer, "-webkit", 7);
6751            ++length;
6752        }
6753    }
6754
6755    const Value* hashTableEntry = findValue(buffer, length);
6756    return hashTableEntry ? hashTableEntry->id : 0;
6757}
6758
6759// "ident" from the CSS tokenizer, minus backslash-escape sequences
6760static bool isCSSTokenizerIdentifier(const String& string)
6761{
6762    const UChar* p = string.characters();
6763    const UChar* end = p + string.length();
6764
6765    // -?
6766    if (p != end && p[0] == '-')
6767        ++p;
6768
6769    // {nmstart}
6770    if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p[0])))
6771        return false;
6772    ++p;
6773
6774    // {nmchar}*
6775    for (; p != end; ++p) {
6776        if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p[0])))
6777            return false;
6778    }
6779
6780    return true;
6781}
6782
6783// "url" from the CSS tokenizer, minus backslash-escape sequences
6784static bool isCSSTokenizerURL(const String& string)
6785{
6786    const UChar* p = string.characters();
6787    const UChar* end = p + string.length();
6788
6789    for (; p != end; ++p) {
6790        UChar c = p[0];
6791        switch (c) {
6792            case '!':
6793            case '#':
6794            case '$':
6795            case '%':
6796            case '&':
6797                break;
6798            default:
6799                if (c < '*')
6800                    return false;
6801                if (c <= '~')
6802                    break;
6803                if (c < 128)
6804                    return false;
6805        }
6806    }
6807
6808    return true;
6809}
6810
6811// We use single quotes for now because markup.cpp uses double quotes.
6812String quoteCSSString(const String& string)
6813{
6814    // For efficiency, we first pre-calculate the length of the quoted string, then we build the actual one.
6815    // Please see below for the actual logic.
6816    unsigned quotedStringSize = 2; // Two quotes surrounding the entire string.
6817    bool afterEscape = false;
6818    for (unsigned i = 0; i < string.length(); ++i) {
6819        UChar ch = string[i];
6820        if (ch == '\\' || ch == '\'') {
6821            quotedStringSize += 2;
6822            afterEscape = false;
6823        } else if (ch < 0x20 || ch == 0x7F) {
6824            quotedStringSize += 2 + (ch >= 0x10);
6825            afterEscape = true;
6826        } else {
6827            quotedStringSize += 1 + (afterEscape && (isASCIIHexDigit(ch) || ch == ' '));
6828            afterEscape = false;
6829        }
6830    }
6831
6832    StringBuffer buffer(quotedStringSize);
6833    unsigned index = 0;
6834    buffer[index++] = '\'';
6835    afterEscape = false;
6836    for (unsigned i = 0; i < string.length(); ++i) {
6837        UChar ch = string[i];
6838        if (ch == '\\' || ch == '\'') {
6839            buffer[index++] = '\\';
6840            buffer[index++] = ch;
6841            afterEscape = false;
6842        } else if (ch < 0x20 || ch == 0x7F) { // Control characters.
6843            buffer[index++] = '\\';
6844            placeByteAsHexCompressIfPossible(ch, buffer, index, Lowercase);
6845            afterEscape = true;
6846        } else {
6847            // Space character may be required to separate backslash-escape sequence and normal characters.
6848            if (afterEscape && (isASCIIHexDigit(ch) || ch == ' '))
6849                buffer[index++] = ' ';
6850            buffer[index++] = ch;
6851            afterEscape = false;
6852        }
6853    }
6854    buffer[index++] = '\'';
6855
6856    ASSERT(quotedStringSize == index);
6857    return String::adopt(buffer);
6858}
6859
6860String quoteCSSStringIfNeeded(const String& string)
6861{
6862    return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string);
6863}
6864
6865String quoteCSSURLIfNeeded(const String& string)
6866{
6867    return isCSSTokenizerURL(string) ? string : quoteCSSString(string);
6868}
6869
6870bool isValidNthToken(const CSSParserString& token)
6871{
6872    // The tokenizer checks for the construct of an+b.
6873    // nth can also accept "odd" or "even" but should not accept any other token.
6874    return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even");
6875}
6876
6877#define YY_DECL int CSSParser::lex()
6878#define yyconst const
6879typedef int yy_state_type;
6880typedef unsigned YY_CHAR;
6881// The following line makes sure we treat non-Latin-1 Unicode characters correctly.
6882#define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
6883#define YY_DO_BEFORE_ACTION \
6884        yytext = yy_bp; \
6885        yyleng = (int) (yy_cp - yy_bp); \
6886        yy_hold_char = *yy_cp; \
6887        *yy_cp = 0; \
6888        yy_c_buf_p = yy_cp;
6889#define YY_BREAK break;
6890#define ECHO
6891#define YY_RULE_SETUP
6892#define INITIAL 0
6893#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
6894#define yyterminate() yyTok = END_TOKEN; return yyTok
6895#define YY_FATAL_ERROR(a)
6896// The following line is needed to build the tokenizer with a condition stack.
6897// The macro is used in the tokenizer grammar with lines containing
6898// BEGIN(mediaqueries) and BEGIN(initial). yy_start acts as index to
6899// tokenizer transition table, and 'mediaqueries' and 'initial' are
6900// offset multipliers that specify which transitions are active
6901// in the tokenizer during in each condition (tokenizer state).
6902#define BEGIN yy_start = 1 + 2 *
6903
6904#include "tokenizer.cpp"
6905
6906}
6907