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