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