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