source: trunk/WebCore/css/CSSParser.cpp @ 63854

Revision 63854, 209.4 KB checked in by commit-queue@webkit.org, 6 years ago (diff)

2010-07-21 Peter Beverloo <peter@lvp-media.com>

Reviewed by Eric Carlson.

Removed support for the -khtml CSS vendor prefix and limit the
-apple prefix to two properties (dashboard-region and line-clamp).

Listed properties in these updated have been changed to -webkit.

  • fast/block/positioning/height-change.html: -apple-box
  • fast/block/positioning/resources/window-height-change-frame-flex.html: -apple-box
  • fast/borders/border-image-omit-right-slice.html: -khtml-border-image
  • fast/css/apple-prefix.html: -khtml-box-orient
  • fast/css/legacy-opacity-styles-expected.txt: -*-opacity
  • fast/css/legacy-opacity-styles.html: -*-opacity
  • fast/css/limited-vendor-prefix-behavior-expected.txt: Added.
  • fast/css/limited-vendor-prefix-behavior.html: Added.
  • fast/flexbox/001.html: -khtml-box-flex
  • fast/flexbox/002.html: -khtml-box, -khtml-box-align, -khtml-box-orient
  • fast/flexbox/003.html: -khtml-box, -khtml-box-align, -khtml-box-orient
  • fast/flexbox/004.html: -khtml-box
  • fast/flexbox/005.html: -khtml-box
  • fast/flexbox/006.html: -khtml-box
  • fast/flexbox/007.html: -khtml-box
  • fast/flexbox/008.html: -khtml-box
  • fast/flexbox/009.html: -khtml-box
  • fast/flexbox/010.html: -khtml-box
  • fast/flexbox/011.html: -khtml-box, -khtml-box-flex
  • fast/flexbox/012.html: -khtml-box, -khtml-box-orient, -khtml-box-align
  • fast/flexbox/013.html: -khtml-box, -khtml-box-flex
  • fast/flexbox/014.html: -khtml-box, -khtml-box-orient, -khtml-box-flex
  • fast/flexbox/015.html: -khtml-box, -khtml-box-flex, -khtml-box-flex
  • fast/flexbox/016.html: -khtml-box-flex, -khtml-box, -khtml-box-orient
  • fast/flexbox/017.html: -khtml-box, -khtml-box-orient, -webkit-box-pack, -khtml-box-direction
  • fast/flexbox/018.html: -khtml-box, -khtml-box-orient, -khtml-box-pack
  • fast/flexbox/019.html: -khtml-box, -khtml-box-pack, -khtml-box-orient
  • fast/flexbox/020.html: -khtml-box, -khtml-box-flex-group, -khtml-box-flex
  • fast/flexbox/021.html: -khtml-box, -khtml-box-flex
  • fast/flexbox/022.html: -khtml-box, -khtml-box-flex
  • fast/flexbox/023.html: -khtml-box
  • fast/flexbox/024.html: -khtml-box, -khtml-box-orient
  • fast/flexbox/025.html: -khtml-box, -khtml-box-flex
  • fast/flexbox/026.html: -khtml-box, -khtml-box-flex
  • fast/flexbox/child-flexing.html: -khtml-box, -khtml-box-align, -khtml-box-orient
  • fast/repaint/flexible-box-overflow-horizontal.html: -khtml-box, -khtml-box-align, -khtml-box-orient
  • fast/repaint/flexible-box-overflow.html: -khtml-box, -khtml-box-align, -khtml-box-orient

2010-07-21 Peter Beverloo <peter@lvp-media.com>

Reviewed by Eric Carlson.

Removed support for the -khtml CSS vendor prefix and limit the
-apple prefix to two properties (dashboard-region and line-clamp).

Test: fast/css/limited-vendor-prefix-behavior.html

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