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