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