OSDN Git Service

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