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