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