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