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