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