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