2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
6 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
7 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
26 #include "CSSParser.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 "CSSPageRule.h"
44 #include "CSSPrimitiveValue.h"
45 #include "CSSProperty.h"
46 #include "CSSPropertyNames.h"
47 #include "CSSQuirkPrimitiveValue.h"
48 #include "CSSReflectValue.h"
49 #include "CSSRuleList.h"
50 #include "CSSSelector.h"
51 #include "CSSStyleRule.h"
52 #include "CSSStyleSheet.h"
53 #include "CSSUnicodeRangeValue.h"
54 #include "CSSValueKeywords.h"
55 #include "CSSValueList.h"
56 #include "CSSVariableDependentValue.h"
57 #include "CSSVariablesDeclaration.h"
58 #include "CSSVariablesRule.h"
61 #include "FloatConversion.h"
62 #include "FontFamilyValue.h"
63 #include "FontValue.h"
64 #include "MediaList.h"
65 #include "MediaQueryExp.h"
68 #include "ShadowValue.h"
69 #include "StringBuffer.h"
70 #include "WebKitCSSKeyframeRule.h"
71 #include "WebKitCSSKeyframesRule.h"
72 #include "WebKitCSSTransformValue.h"
76 #if ENABLE(DASHBOARD_SUPPORT)
77 #include "DashboardRegion.h"
83 extern int cssyydebug;
86 extern int cssyyparse(void* parser);
91 #include "CSSPropertyNames.cpp"
92 #include "CSSValueKeywords.cpp"
94 #ifdef ANDROID_INSTRUMENT
95 #include "TimeCounter.h"
100 static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
102 static bool equal(const CSSParserString& a, const char* b)
104 for (int i = 0; i < a.length; ++i) {
107 if (a.characters[i] != b[i])
113 static bool equalIgnoringCase(const CSSParserString& a, const char* b)
115 for (int i = 0; i < a.length; ++i) {
118 ASSERT(!isASCIIUpper(b[i]));
119 if (toASCIILower(a.characters[i]) != b[i])
125 static bool hasPrefix(const char* string, unsigned length, const char* prefix)
127 for (unsigned i = 0; i < length; ++i) {
130 if (string[i] != prefix[i])
136 CSSParser::CSSParser(bool strictParsing)
137 : m_strict(strictParsing)
143 , m_parsedProperties(static_cast<CSSProperty**>(fastMalloc(32 * sizeof(CSSProperty*))))
144 , m_numParsedProperties(0)
145 , m_maxParsedProperties(32)
146 , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
147 , m_inParseShorthand(0)
148 , m_currentShorthand(0)
149 , m_implicitShorthand(false)
150 , m_hasFontFaceOnlyValues(false)
151 , m_hadSyntacticallyValidCSSRule(false)
152 , m_defaultNamespace(starAtom)
153 , m_ruleBodyStartOffset(0)
154 , m_ruleBodyEndOffset(0)
159 , m_lastSelectorLineNumber(0)
160 , m_allowImportRules(true)
161 , m_allowVariablesRules(true)
162 , m_allowNamespaceDeclarations(true)
163 , m_floatingMediaQuery(0)
164 , m_floatingMediaQueryExp(0)
165 , m_floatingMediaQueryExpList(0)
172 CSSParser::~CSSParser()
175 fastFree(m_parsedProperties);
183 if (m_floatingMediaQueryExpList) {
184 deleteAllValues(*m_floatingMediaQueryExpList);
185 delete m_floatingMediaQueryExpList;
187 delete m_floatingMediaQueryExp;
188 delete m_floatingMediaQuery;
189 fastDeleteAllValues(m_floatingSelectors);
190 deleteAllValues(m_floatingValueLists);
191 deleteAllValues(m_floatingFunctions);
192 deleteAllValues(m_reusableSelectorVector);
195 void CSSParserString::lower()
197 // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
198 // that can potentially change the length of the string rather than the character
199 // by character kind. If we don't need Unicode lowercasing, it would be good to
200 // simplify this function.
202 if (charactersAreAllASCII(characters, length)) {
203 // Fast case for all-ASCII.
204 for (int i = 0; i < length; i++)
205 characters[i] = toASCIILower(characters[i]);
207 for (int i = 0; i < length; i++)
208 characters[i] = Unicode::toLower(characters[i]);
212 void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix)
214 int length = string.length() + strlen(prefix) + strlen(suffix) + 2;
217 m_data = static_cast<UChar*>(fastMalloc(length * sizeof(UChar)));
218 for (unsigned i = 0; i < strlen(prefix); i++)
219 m_data[i] = prefix[i];
221 memcpy(m_data + strlen(prefix), string.characters(), string.length() * sizeof(UChar));
223 unsigned start = strlen(prefix) + string.length();
224 unsigned end = start + strlen(suffix);
225 for (unsigned i = start; i < end; i++)
226 m_data[i] = suffix[i - start];
228 m_data[length - 1] = 0;
229 m_data[length - 2] = 0;
233 yytext = yy_c_buf_p = m_data;
234 yy_hold_char = *yy_c_buf_p;
235 resetRuleBodyMarks();
238 void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string, int startLineNumber, StyleRuleRanges* ruleRangeMap)
240 #ifdef ANDROID_INSTRUMENT
241 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
243 m_styleSheet = sheet;
244 m_defaultNamespace = starAtom; // Reset the default namespace.
245 m_ruleRanges = ruleRangeMap;
247 m_lineNumber = startLineNumber;
248 setupParser("", string, "");
252 #ifdef ANDROID_INSTRUMENT
253 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
257 PassRefPtr<CSSRule> CSSParser::parseRule(CSSStyleSheet* sheet, const String& string)
259 #ifdef ANDROID_INSTRUMENT
260 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
262 m_styleSheet = sheet;
263 m_allowNamespaceDeclarations = false;
264 setupParser("@-webkit-rule{", string, "} ");
266 #ifdef ANDROID_INSTRUMENT
267 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
269 return m_rule.release();
272 PassRefPtr<CSSRule> CSSParser::parseKeyframeRule(CSSStyleSheet *sheet, const String &string)
274 #ifdef ANDROID_INSTRUMENT
275 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
277 m_styleSheet = sheet;
278 setupParser("@-webkit-keyframe-rule{ ", string, "} ");
280 #ifdef ANDROID_INSTRUMENT
281 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
283 return m_keyframe.release();
286 bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int id, const String& string, bool important)
288 #ifdef ANDROID_INSTRUMENT
289 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
291 ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
292 m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
294 setupParser("@-webkit-value{", string, "} ");
297 m_important = important;
304 if (m_hasFontFaceOnlyValues)
305 deleteFontFaceOnlyValues();
306 if (m_numParsedProperties) {
308 declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
312 #ifdef ANDROID_INSTRUMENT
313 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
318 // color will only be changed when string contains a valid css color, making it
319 // possible to set up a default color.
320 bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
322 // First try creating a color specified by name, rgb() or "#" syntax.
323 if (parseColor(string, color, strict))
326 CSSParser parser(true);
327 RefPtr<CSSMutableStyleDeclaration> dummyStyleDeclaration = CSSMutableStyleDeclaration::create();
329 // Now try to create a color from rgba() syntax.
330 if (!parser.parseColor(dummyStyleDeclaration.get(), string))
333 CSSValue* value = parser.m_parsedProperties[0]->value();
334 if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) {
335 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
336 color = primitiveValue->getRGBA32Value();
342 bool CSSParser::parseColor(CSSMutableStyleDeclaration* declaration, const String& string)
344 #ifdef ANDROID_INSTRUMENT
345 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
347 ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
348 m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
350 setupParser("@-webkit-decls{color:", string, "} ");
354 #ifdef ANDROID_INSTRUMENT
355 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
357 return (m_numParsedProperties && m_parsedProperties[0]->m_id == CSSPropertyColor);
360 void CSSParser::parseSelector(const String& string, Document* doc, CSSSelectorList& selectorList)
362 #ifdef ANDROID_INSTRUMENT
363 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
365 RefPtr<CSSStyleSheet> dummyStyleSheet = CSSStyleSheet::create(doc);
367 m_styleSheet = dummyStyleSheet.get();
368 m_selectorListForParseSelector = &selectorList;
370 setupParser("@-webkit-selector{", string, "}");
374 m_selectorListForParseSelector = 0;
375 #ifdef ANDROID_INSTRUMENT
376 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
380 bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration* declaration, const String& string)
382 #ifdef ANDROID_INSTRUMENT
383 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
385 ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
386 m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
388 setupParser("@-webkit-decls{", string, "} ");
393 if (m_hasFontFaceOnlyValues)
394 deleteFontFaceOnlyValues();
395 if (m_numParsedProperties) {
397 declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
401 #ifdef ANDROID_INSTRUMENT
402 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
407 bool CSSParser::parseMediaQuery(MediaList* queries, const String& string)
409 if (string.isEmpty())
412 #ifdef ANDROID_INSTRUMENT
413 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
416 // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
417 // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
418 setupParser("@-webkit-mediaquery ", string, "} ");
424 queries->appendMediaQuery(m_mediaQuery);
428 #ifdef ANDROID_INSTRUMENT
429 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
435 void CSSParser::addProperty(int propId, PassRefPtr<CSSValue> value, bool important)
437 OwnPtr<CSSProperty> prop(new CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand));
438 if (m_numParsedProperties >= m_maxParsedProperties) {
439 m_maxParsedProperties += 32;
440 if (m_maxParsedProperties > UINT_MAX / sizeof(CSSProperty*))
442 m_parsedProperties = static_cast<CSSProperty**>(fastRealloc(m_parsedProperties,
443 m_maxParsedProperties * sizeof(CSSProperty*)));
445 m_parsedProperties[m_numParsedProperties++] = prop.leakPtr();
448 void CSSParser::rollbackLastProperties(int num)
451 ASSERT(m_numParsedProperties >= static_cast<unsigned>(num));
453 for (int i = 0; i < num; ++i)
454 delete m_parsedProperties[--m_numParsedProperties];
457 void CSSParser::clearProperties()
459 for (unsigned i = 0; i < m_numParsedProperties; i++)
460 delete m_parsedProperties[i];
461 m_numParsedProperties = 0;
462 m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
463 m_hasFontFaceOnlyValues = false;
466 Document* CSSParser::document() const
468 StyleBase* root = m_styleSheet;
470 while (root && root->parent())
471 root = root->parent();
472 if (root && root->isCSSStyleSheet())
473 doc = static_cast<CSSStyleSheet*>(root)->doc();
477 bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, bool strict)
480 switch (value->unit) {
481 case CSSPrimitiveValue::CSS_NUMBER:
482 b = (unitflags & FNumber);
483 if (!b && ((unitflags & (FLength | FAngle | FTime)) && (value->fValue == 0 || !strict))) {
484 value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
485 ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
488 if (!b && (unitflags & FInteger) && value->isInt)
491 case CSSPrimitiveValue::CSS_PERCENTAGE:
492 b = (unitflags & FPercent);
494 case CSSParserValue::Q_EMS:
495 case CSSPrimitiveValue::CSS_EMS:
496 case CSSPrimitiveValue::CSS_REMS:
497 case CSSPrimitiveValue::CSS_EXS:
498 case CSSPrimitiveValue::CSS_PX:
499 case CSSPrimitiveValue::CSS_CM:
500 case CSSPrimitiveValue::CSS_MM:
501 case CSSPrimitiveValue::CSS_IN:
502 case CSSPrimitiveValue::CSS_PT:
503 case CSSPrimitiveValue::CSS_PC:
504 b = (unitflags & FLength);
506 case CSSPrimitiveValue::CSS_MS:
507 case CSSPrimitiveValue::CSS_S:
508 b = (unitflags & FTime);
510 case CSSPrimitiveValue::CSS_DEG:
511 case CSSPrimitiveValue::CSS_RAD:
512 case CSSPrimitiveValue::CSS_GRAD:
513 case CSSPrimitiveValue::CSS_TURN:
514 b = (unitflags & FAngle);
516 case CSSPrimitiveValue::CSS_HZ:
517 case CSSPrimitiveValue::CSS_KHZ:
518 case CSSPrimitiveValue::CSS_DIMENSION:
522 if (b && unitflags & FNonNeg && value->fValue < 0)
527 static int unitFromString(CSSParserValue* value)
529 if (value->unit != CSSPrimitiveValue::CSS_IDENT || value->id)
532 if (equal(value->string, "em"))
533 return CSSPrimitiveValue::CSS_EMS;
534 if (equal(value->string, "rem"))
535 return CSSPrimitiveValue::CSS_REMS;
536 if (equal(value->string, "ex"))
537 return CSSPrimitiveValue::CSS_EXS;
538 if (equal(value->string, "px"))
539 return CSSPrimitiveValue::CSS_PX;
540 if (equal(value->string, "cm"))
541 return CSSPrimitiveValue::CSS_CM;
542 if (equal(value->string, "mm"))
543 return CSSPrimitiveValue::CSS_MM;
544 if (equal(value->string, "in"))
545 return CSSPrimitiveValue::CSS_IN;
546 if (equal(value->string, "pt"))
547 return CSSPrimitiveValue::CSS_PT;
548 if (equal(value->string, "pc"))
549 return CSSPrimitiveValue::CSS_PC;
550 if (equal(value->string, "deg"))
551 return CSSPrimitiveValue::CSS_DEG;
552 if (equal(value->string, "rad"))
553 return CSSPrimitiveValue::CSS_RAD;
554 if (equal(value->string, "grad"))
555 return CSSPrimitiveValue::CSS_GRAD;
556 if (equal(value->string, "turn"))
557 return CSSPrimitiveValue::CSS_TURN;
558 if (equal(value->string, "ms"))
559 return CSSPrimitiveValue::CSS_MS;
560 if (equal(value->string, "s"))
561 return CSSPrimitiveValue::CSS_S;
562 if (equal(value->string, "Hz"))
563 return CSSPrimitiveValue::CSS_HZ;
564 if (equal(value->string, "kHz"))
565 return CSSPrimitiveValue::CSS_KHZ;
570 void CSSParser::checkForOrphanedUnits()
572 if (m_strict || inShorthand())
575 // The purpose of this code is to implement the WinIE quirk that allows unit types to be separated from their numeric values
576 // 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.
577 CSSParserValue* numericVal = 0;
578 unsigned size = m_valueList->size();
579 for (unsigned i = 0; i < size; i++) {
580 CSSParserValue* value = m_valueList->valueAt(i);
583 // Change the unit type of the numeric val to match.
584 int unit = unitFromString(value);
586 numericVal->unit = unit;
589 // Now delete the bogus unit value.
590 m_valueList->deleteValueAt(i);
591 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).
597 numericVal = (value->unit == CSSPrimitiveValue::CSS_NUMBER) ? value : 0;
601 bool CSSParser::parseValue(int propId, bool important)
606 CSSParserValue *value = m_valueList->current();
613 // In quirks mode, we will look for units that have been incorrectly separated from the number they belong to
614 // by a space. We go ahead and associate the unit with the number even though it is invalid CSS.
615 checkForOrphanedUnits();
617 int num = inShorthand() ? 1 : m_valueList->size();
619 if (id == CSSValueInherit) {
622 addProperty(propId, CSSInheritedValue::create(), important);
625 else if (id == CSSValueInitial) {
628 addProperty(propId, CSSInitialValue::createExplicit(), important);
632 // If we have any variables, then we don't parse the list of values yet. We add them to the declaration
633 // as unresolved, and allow them to be parsed later. The parse is considered "successful" for now, even though
634 // it might ultimately fail once the variable has been resolved.
635 if (!inShorthand() && checkForVariables(m_valueList)) {
636 addUnresolvedProperty(propId, important);
640 bool validPrimitive = false;
641 RefPtr<CSSValue> parsedValue;
643 switch (static_cast<CSSPropertyID>(propId)) {
644 /* The comment to the left defines all valid value of this properties as defined
645 * in CSS 2, Appendix F. Property index
648 /* All the CSS properties are not supported by the renderer at the moment.
649 * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
650 * (see parseAuralValues). As we don't support them at all this seems reasonable.
653 case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
654 return parseSize(propId, important);
656 case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit
658 validPrimitive = true;
660 case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | inherit
661 if (id == CSSValueNormal ||
662 id == CSSValueEmbed ||
663 id == CSSValueBidiOverride)
664 validPrimitive = true;
667 case CSSPropertyPosition: // static | relative | absolute | fixed | inherit
668 if (id == CSSValueStatic ||
669 id == CSSValueRelative ||
670 id == CSSValueAbsolute ||
672 validPrimitive = true;
675 case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit
676 case CSSPropertyPageBreakBefore:
677 case CSSPropertyWebkitColumnBreakAfter:
678 case CSSPropertyWebkitColumnBreakBefore:
679 if (id == CSSValueAuto ||
680 id == CSSValueAlways ||
681 id == CSSValueAvoid ||
682 id == CSSValueLeft ||
684 validPrimitive = true;
687 case CSSPropertyPageBreakInside: // avoid | auto | inherit
688 case CSSPropertyWebkitColumnBreakInside:
689 if (id == CSSValueAuto || id == CSSValueAvoid)
690 validPrimitive = true;
693 case CSSPropertyEmptyCells: // show | hide | inherit
694 if (id == CSSValueShow ||
696 validPrimitive = true;
699 case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
700 // close-quote | no-open-quote | no-close-quote ]+ | inherit
701 return parseContent(propId, important);
703 case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit
704 if (id == CSSValueNormal ||
706 id == CSSValuePreWrap ||
707 id == CSSValuePreLine ||
708 id == CSSValueNowrap)
709 validPrimitive = true;
712 case CSSPropertyClip: // <shape> | auto | inherit
713 if (id == CSSValueAuto)
714 validPrimitive = true;
715 else if (value->unit == CSSParserValue::Function)
716 return parseShape(propId, important);
719 /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
720 * correctly and allows optimization in WebCore::applyRule(..)
722 case CSSPropertyCaptionSide: // top | bottom | left | right | inherit
723 if (id == CSSValueLeft || id == CSSValueRight ||
724 id == CSSValueTop || id == CSSValueBottom)
725 validPrimitive = true;
728 case CSSPropertyBorderCollapse: // collapse | separate | inherit
729 if (id == CSSValueCollapse || id == CSSValueSeparate)
730 validPrimitive = true;
733 case CSSPropertyVisibility: // visible | hidden | collapse | inherit
734 if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueCollapse)
735 validPrimitive = true;
738 case CSSPropertyOverflow: {
739 ShorthandScope scope(this, propId);
740 if (num != 1 || !parseValue(CSSPropertyOverflowX, important))
742 CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value();
743 addProperty(CSSPropertyOverflowY, value, important);
746 case CSSPropertyOverflowX:
747 case CSSPropertyOverflowY: // visible | hidden | scroll | auto | marquee | overlay | inherit
748 if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueScroll || id == CSSValueAuto ||
749 id == CSSValueOverlay || id == CSSValueWebkitMarquee)
750 validPrimitive = true;
753 case CSSPropertyListStylePosition: // inside | outside | inherit
754 if (id == CSSValueInside || id == CSSValueOutside)
755 validPrimitive = true;
758 case CSSPropertyListStyleType:
759 // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
760 // for the list of supported list-style-types.
761 if ((id >= CSSValueDisc && id <= CSSValueKatakanaIroha) || id == CSSValueNone)
762 validPrimitive = true;
765 case CSSPropertyDisplay:
766 // inline | block | list-item | run-in | inline-block | table |
767 // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
768 // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit
770 if ((id >= CSSValueInline && id <= CSSValueWapMarquee) || id == CSSValueNone)
772 if ((id >= CSSValueInline && id <= CSSValueWebkitInlineBox) || id == CSSValueNone)
774 validPrimitive = true;
777 case CSSPropertyDirection: // ltr | rtl | inherit
778 if (id == CSSValueLtr || id == CSSValueRtl)
779 validPrimitive = true;
782 case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit
783 if ((id >= CSSValueCapitalize && id <= CSSValueLowercase) || id == CSSValueNone)
784 validPrimitive = true;
787 case CSSPropertyFloat: // left | right | none | inherit + center for buggy CSS
788 if (id == CSSValueLeft || id == CSSValueRight ||
789 id == CSSValueNone || id == CSSValueCenter)
790 validPrimitive = true;
793 case CSSPropertyClear: // none | left | right | both | inherit
794 if (id == CSSValueNone || id == CSSValueLeft ||
795 id == CSSValueRight|| id == CSSValueBoth)
796 validPrimitive = true;
799 case CSSPropertyTextAlign:
800 // left | right | center | justify | webkit_left | webkit_right | webkit_center | start | end | <string> | inherit
801 if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitCenter) || id == CSSValueStart || id == CSSValueEnd ||
802 value->unit == CSSPrimitiveValue::CSS_STRING)
803 validPrimitive = true;
806 case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit
807 if (id == CSSValueAuto || id == CSSValueNone || (id >= CSSValueInset && id <= CSSValueDouble))
808 validPrimitive = true;
811 case CSSPropertyBorderTopStyle: //// <border-style> | inherit
812 case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
813 case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
814 case CSSPropertyBorderLeftStyle:
815 case CSSPropertyWebkitBorderStartStyle:
816 case CSSPropertyWebkitBorderEndStyle:
817 case CSSPropertyWebkitColumnRuleStyle:
818 if (id >= CSSValueNone && id <= CSSValueDouble)
819 validPrimitive = true;
822 case CSSPropertyFontWeight: // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
823 return parseFontWeight(important);
825 case CSSPropertyBorderSpacing: {
826 const int properties[2] = { CSSPropertyWebkitBorderHorizontalSpacing,
827 CSSPropertyWebkitBorderVerticalSpacing };
829 ShorthandScope scope(this, CSSPropertyBorderSpacing);
830 if (!parseValue(properties[0], important))
832 CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value();
833 addProperty(properties[1], value, important);
837 ShorthandScope scope(this, CSSPropertyBorderSpacing);
838 if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
844 case CSSPropertyWebkitBorderHorizontalSpacing:
845 case CSSPropertyWebkitBorderVerticalSpacing:
846 validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
848 case CSSPropertyOutlineColor: // <color> | invert | inherit
849 // Outline color has "invert" as additional keyword.
850 // Also, we want to allow the special focus color even in strict parsing mode.
851 if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
852 validPrimitive = true;
856 case CSSPropertyBackgroundColor: // <color> | inherit
857 case CSSPropertyBorderTopColor: // <color> | inherit
858 case CSSPropertyBorderRightColor:
859 case CSSPropertyBorderBottomColor:
860 case CSSPropertyBorderLeftColor:
861 case CSSPropertyWebkitBorderStartColor:
862 case CSSPropertyWebkitBorderEndColor:
863 case CSSPropertyColor: // <color> | inherit
864 case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors
865 case CSSPropertyTextUnderlineColor:
866 case CSSPropertyTextOverlineColor:
867 case CSSPropertyWebkitColumnRuleColor:
868 case CSSPropertyWebkitTextFillColor:
869 case CSSPropertyWebkitTextStrokeColor:
870 if (id == CSSValueWebkitText)
871 validPrimitive = true; // Always allow this, even when strict parsing is on,
872 // since we use this in our UA sheets.
873 else if (id == CSSValueCurrentcolor)
874 validPrimitive = true;
875 else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu ||
876 (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && !m_strict)) {
877 validPrimitive = true;
879 parsedValue = parseColor();
885 case CSSPropertyCursor: {
886 // [<uri>,]* [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
887 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
888 // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
889 // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
890 // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
891 RefPtr<CSSValueList> list;
892 while (value && value->unit == CSSPrimitiveValue::CSS_URI) {
894 list = CSSValueList::createCommaSeparated();
895 String uri = value->string;
897 value = m_valueList->next();
898 while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
899 coords.append(int(value->fValue));
900 value = m_valueList->next();
902 IntPoint hotSpot(-1, -1);
903 int nrcoords = coords.size();
904 if (nrcoords > 0 && nrcoords != 2)
907 hotSpot = IntPoint(coords[0], coords[1]);
909 if (!uri.isNull() && m_styleSheet) {
910 // FIXME: The completeURL call should be done when using the CSSCursorImageValue,
911 // not when creating it.
912 list->append(CSSCursorImageValue::create(m_styleSheet->completeURL(uri), hotSpot));
915 if ((m_strict && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ',')))
917 value = m_valueList->next(); // comma
920 if (!value) { // no value after url list (MSIE 5 compatibility)
921 if (list->length() != 1)
923 } else if (!m_strict && value->id == CSSValueHand) // MSIE 5 compatibility :/
924 list->append(CSSPrimitiveValue::createIdentifier(CSSValuePointer));
925 else if (value && ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone))
926 list->append(CSSPrimitiveValue::createIdentifier(value->id));
928 parsedValue = list.release();
932 if (!m_strict && value->id == CSSValueHand) { // MSIE 5 compatibility :/
933 id = CSSValuePointer;
934 validPrimitive = true;
935 } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
936 validPrimitive = true;
940 case CSSPropertyBackgroundAttachment:
941 case CSSPropertyBackgroundClip:
942 case CSSPropertyWebkitBackgroundClip:
943 case CSSPropertyWebkitBackgroundComposite:
944 case CSSPropertyBackgroundImage:
945 case CSSPropertyBackgroundOrigin:
946 case CSSPropertyWebkitBackgroundOrigin:
947 case CSSPropertyBackgroundPosition:
948 case CSSPropertyBackgroundPositionX:
949 case CSSPropertyBackgroundPositionY:
950 case CSSPropertyBackgroundSize:
951 case CSSPropertyWebkitBackgroundSize:
952 case CSSPropertyBackgroundRepeat:
953 case CSSPropertyBackgroundRepeatX:
954 case CSSPropertyBackgroundRepeatY:
955 case CSSPropertyWebkitMaskAttachment:
956 case CSSPropertyWebkitMaskClip:
957 case CSSPropertyWebkitMaskComposite:
958 case CSSPropertyWebkitMaskImage:
959 case CSSPropertyWebkitMaskOrigin:
960 case CSSPropertyWebkitMaskPosition:
961 case CSSPropertyWebkitMaskPositionX:
962 case CSSPropertyWebkitMaskPositionY:
963 case CSSPropertyWebkitMaskSize:
964 case CSSPropertyWebkitMaskRepeat:
965 case CSSPropertyWebkitMaskRepeatX:
966 case CSSPropertyWebkitMaskRepeatY: {
967 RefPtr<CSSValue> val1;
968 RefPtr<CSSValue> val2;
969 int propId1, propId2;
971 if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
972 OwnPtr<ShorthandScope> shorthandScope;
973 if (propId == CSSPropertyBackgroundPosition ||
974 propId == CSSPropertyBackgroundRepeat ||
975 propId == CSSPropertyWebkitMaskPosition ||
976 propId == CSSPropertyWebkitMaskRepeat) {
977 shorthandScope.set(new ShorthandScope(this, propId));
979 addProperty(propId1, val1.release(), important);
981 addProperty(propId2, val2.release(), important);
984 m_implicitShorthand = false;
987 case CSSPropertyListStyleImage: // <uri> | none | inherit
988 if (id == CSSValueNone) {
989 parsedValue = CSSImageValue::create();
991 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
993 // FIXME: The completeURL call should be done when using the CSSImageValue,
994 // not when creating it.
995 parsedValue = CSSImageValue::create(m_styleSheet->completeURL(value->string));
998 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-gradient(")) {
999 if (parseGradient(parsedValue))
1000 m_valueList->next();
1006 case CSSPropertyWebkitTextStrokeWidth:
1007 case CSSPropertyOutlineWidth: // <border-width> | inherit
1008 case CSSPropertyBorderTopWidth: //// <border-width> | inherit
1009 case CSSPropertyBorderRightWidth: // Which is defined as
1010 case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
1011 case CSSPropertyBorderLeftWidth:
1012 case CSSPropertyWebkitBorderStartWidth:
1013 case CSSPropertyWebkitBorderEndWidth:
1014 case CSSPropertyWebkitColumnRuleWidth:
1015 if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
1016 validPrimitive = true;
1018 validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
1021 case CSSPropertyLetterSpacing: // normal | <length> | inherit
1022 case CSSPropertyWordSpacing: // normal | <length> | inherit
1023 if (id == CSSValueNormal)
1024 validPrimitive = true;
1026 validPrimitive = validUnit(value, FLength, m_strict);
1029 case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
1030 if (id == CSSValueNormal || id == CSSValueBreakAll || id == CSSValueBreakWord)
1031 validPrimitive = true;
1034 case CSSPropertyWordWrap: // normal | break-word
1035 if (id == CSSValueNormal || id == CSSValueBreakWord)
1036 validPrimitive = true;
1039 case CSSPropertyTextIndent: // <length> | <percentage> | inherit
1040 validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
1043 case CSSPropertyPaddingTop: //// <padding-width> | inherit
1044 case CSSPropertyPaddingRight: // Which is defined as
1045 case CSSPropertyPaddingBottom: // <length> | <percentage>
1046 case CSSPropertyPaddingLeft: ////
1047 case CSSPropertyWebkitPaddingStart:
1048 case CSSPropertyWebkitPaddingEnd:
1049 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
1052 case CSSPropertyMaxHeight: // <length> | <percentage> | none | inherit
1053 case CSSPropertyMaxWidth: // <length> | <percentage> | none | inherit
1054 if (id == CSSValueNone || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) {
1055 validPrimitive = true;
1059 case CSSPropertyMinHeight: // <length> | <percentage> | inherit
1060 case CSSPropertyMinWidth: // <length> | <percentage> | inherit
1061 if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
1062 validPrimitive = true;
1064 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
1067 case CSSPropertyFontSize:
1068 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
1069 if (id >= CSSValueXxSmall && id <= CSSValueLarger)
1070 validPrimitive = true;
1072 validPrimitive = (validUnit(value, FLength | FPercent | FNonNeg, m_strict));
1075 case CSSPropertyFontStyle: // normal | italic | oblique | inherit
1076 return parseFontStyle(important);
1078 case CSSPropertyFontVariant: // normal | small-caps | inherit
1079 return parseFontVariant(important);
1081 case CSSPropertyVerticalAlign:
1082 // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
1083 // <percentage> | <length> | inherit
1085 if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
1086 validPrimitive = true;
1088 validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
1091 case CSSPropertyHeight: // <length> | <percentage> | auto | inherit
1092 case CSSPropertyWidth: // <length> | <percentage> | auto | inherit
1093 if (id == CSSValueAuto || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
1094 validPrimitive = true;
1096 // ### handle multilength case where we allow relative units
1097 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
1100 case CSSPropertyBottom: // <length> | <percentage> | auto | inherit
1101 case CSSPropertyLeft: // <length> | <percentage> | auto | inherit
1102 case CSSPropertyRight: // <length> | <percentage> | auto | inherit
1103 case CSSPropertyTop: // <length> | <percentage> | auto | inherit
1104 case CSSPropertyMarginTop: //// <margin-width> | inherit
1105 case CSSPropertyMarginRight: // Which is defined as
1106 case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit
1107 case CSSPropertyMarginLeft: ////
1108 case CSSPropertyWebkitMarginStart:
1109 case CSSPropertyWebkitMarginEnd:
1110 if (id == CSSValueAuto)
1111 validPrimitive = true;
1113 validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
1116 case CSSPropertyZIndex: // auto | <integer> | inherit
1117 if (id == CSSValueAuto) {
1118 validPrimitive = true;
1122 case CSSPropertyOrphans: // <integer> | inherit
1123 case CSSPropertyWidows: // <integer> | inherit
1124 // ### not supported later on
1125 validPrimitive = (!id && validUnit(value, FInteger, false));
1128 case CSSPropertyLineHeight: // normal | <number> | <length> | <percentage> | inherit
1129 if (id == CSSValueNormal)
1130 validPrimitive = true;
1132 validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict));
1134 case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
1135 if (id != CSSValueNone)
1136 return parseCounter(propId, 1, important);
1137 validPrimitive = true;
1139 case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit
1140 if (id != CSSValueNone)
1141 return parseCounter(propId, 0, important);
1142 validPrimitive = true;
1144 case CSSPropertyFontFamily:
1145 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
1147 parsedValue = parseFontFamily();
1151 case CSSPropertyTextDecoration:
1152 case CSSPropertyWebkitTextDecorationsInEffect:
1153 // none | [ underline || overline || line-through || blink ] | inherit
1154 if (id == CSSValueNone) {
1155 validPrimitive = true;
1157 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
1158 bool isValid = true;
1159 while (isValid && value) {
1160 switch (value->id) {
1163 case CSSValueUnderline:
1164 case CSSValueOverline:
1165 case CSSValueLineThrough:
1166 list->append(CSSPrimitiveValue::createIdentifier(value->id));
1171 value = m_valueList->next();
1173 if (list->length() && isValid) {
1174 parsedValue = list.release();
1175 m_valueList->next();
1180 case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit
1181 if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
1182 validPrimitive = true;
1184 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, true));
1187 case CSSPropertyTableLayout: // auto | fixed | inherit
1188 if (id == CSSValueAuto || id == CSSValueFixed)
1189 validPrimitive = true;
1192 case CSSPropertySrc: // Only used within @font-face, so cannot use inherit | initial or be !important. This is a list of urls or local references.
1193 return parseFontFaceSrc();
1195 case CSSPropertyUnicodeRange:
1196 return parseFontFaceUnicodeRange();
1198 /* CSS3 properties */
1199 case CSSPropertyWebkitAppearance:
1200 if ((id >= CSSValueCheckbox && id <= CSSValueTextarea) || id == CSSValueNone)
1201 validPrimitive = true;
1204 case CSSPropertyWebkitBinding:
1206 if (id == CSSValueNone)
1207 validPrimitive = true;
1209 RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
1210 CSSParserValue* val;
1211 RefPtr<CSSValue> parsedValue;
1212 while ((val = m_valueList->current())) {
1213 if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
1214 // FIXME: The completeURL call should be done when using the CSSPrimitiveValue,
1215 // not when creating it.
1216 parsedValue = CSSPrimitiveValue::create(m_styleSheet->completeURL(val->string), CSSPrimitiveValue::CSS_URI);
1221 // FIXME: We can't use release() here since we might hit this path twice
1222 // but that logic seems wrong to me to begin with, we convert all non-uri values
1223 // into the last seen URI value!?
1224 // -webkit-binding: url(foo.xml), 1, 2; (if that were valid) is treated as:
1225 // -webkit-binding: url(foo.xml), url(foo.xml), url(foo.xml); !?
1226 values->append(parsedValue.get());
1227 m_valueList->next();
1229 if (!values->length())
1232 addProperty(propId, values.release(), important);
1233 m_valueList->next();
1238 case CSSPropertyWebkitBorderImage:
1239 case CSSPropertyWebkitMaskBoxImage:
1240 if (id == CSSValueNone)
1241 validPrimitive = true;
1243 RefPtr<CSSValue> result;
1244 if (parseBorderImage(propId, important, result)) {
1245 addProperty(propId, result, important);
1250 case CSSPropertyBorderTopRightRadius:
1251 case CSSPropertyBorderTopLeftRadius:
1252 case CSSPropertyBorderBottomLeftRadius:
1253 case CSSPropertyBorderBottomRightRadius: {
1254 if (num != 1 && num != 2)
1256 validPrimitive = validUnit(value, FLength, m_strict);
1257 if (!validPrimitive)
1259 RefPtr<CSSPrimitiveValue> parsedValue1 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1260 RefPtr<CSSPrimitiveValue> parsedValue2;
1262 value = m_valueList->next();
1263 validPrimitive = validUnit(value, FLength, m_strict);
1264 if (!validPrimitive)
1266 parsedValue2 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1268 parsedValue2 = parsedValue1;
1270 RefPtr<Pair> pair = Pair::create(parsedValue1.release(), parsedValue2.release());
1271 RefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(pair.release());
1272 addProperty(propId, val.release(), important);
1275 case CSSPropertyBorderRadius:
1276 case CSSPropertyWebkitBorderRadius:
1277 return parseBorderRadius(propId, important);
1278 case CSSPropertyOutlineOffset:
1279 validPrimitive = validUnit(value, FLength, m_strict);
1281 case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
1282 case CSSPropertyWebkitBoxShadow:
1283 if (id == CSSValueNone)
1284 validPrimitive = true;
1286 return parseShadow(propId, important);
1288 case CSSPropertyWebkitBoxReflect:
1289 if (id == CSSValueNone)
1290 validPrimitive = true;
1292 return parseReflect(propId, important);
1294 case CSSPropertyOpacity:
1295 validPrimitive = validUnit(value, FNumber, m_strict);
1297 case CSSPropertyWebkitBoxAlign:
1298 if (id == CSSValueStretch || id == CSSValueStart || id == CSSValueEnd ||
1299 id == CSSValueCenter || id == CSSValueBaseline)
1300 validPrimitive = true;
1302 case CSSPropertyWebkitBoxDirection:
1303 if (id == CSSValueNormal || id == CSSValueReverse)
1304 validPrimitive = true;
1306 case CSSPropertyWebkitBoxLines:
1307 if (id == CSSValueSingle || id == CSSValueMultiple)
1308 validPrimitive = true;
1310 case CSSPropertyWebkitBoxOrient:
1311 if (id == CSSValueHorizontal || id == CSSValueVertical ||
1312 id == CSSValueInlineAxis || id == CSSValueBlockAxis)
1313 validPrimitive = true;
1315 case CSSPropertyWebkitBoxPack:
1316 if (id == CSSValueStart || id == CSSValueEnd ||
1317 id == CSSValueCenter || id == CSSValueJustify)
1318 validPrimitive = true;
1320 case CSSPropertyWebkitBoxFlex:
1321 validPrimitive = validUnit(value, FNumber, m_strict);
1323 case CSSPropertyWebkitBoxFlexGroup:
1324 case CSSPropertyWebkitBoxOrdinalGroup:
1325 validPrimitive = validUnit(value, FInteger | FNonNeg, true);
1327 case CSSPropertyWebkitBoxSizing:
1328 validPrimitive = id == CSSValueBorderBox || id == CSSValueContentBox;
1330 case CSSPropertyWebkitColorCorrection:
1331 validPrimitive = id == CSSValueSrgb || id == CSSValueDefault;
1333 case CSSPropertyWebkitMarquee: {
1334 const int properties[5] = { CSSPropertyWebkitMarqueeDirection, CSSPropertyWebkitMarqueeIncrement,
1335 CSSPropertyWebkitMarqueeRepetition,
1336 CSSPropertyWebkitMarqueeStyle, CSSPropertyWebkitMarqueeSpeed };
1337 return parseShorthand(propId, properties, 5, important);
1339 case CSSPropertyWebkitMarqueeDirection:
1340 if (id == CSSValueForwards || id == CSSValueBackwards || id == CSSValueAhead ||
1341 id == CSSValueReverse || id == CSSValueLeft || id == CSSValueRight || id == CSSValueDown ||
1342 id == CSSValueUp || id == CSSValueAuto)
1343 validPrimitive = true;
1345 case CSSPropertyWebkitMarqueeIncrement:
1346 if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
1347 validPrimitive = true;
1349 validPrimitive = validUnit(value, FLength | FPercent, m_strict);
1351 case CSSPropertyWebkitMarqueeStyle:
1352 if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate)
1353 validPrimitive = true;
1355 case CSSPropertyWebkitMarqueeRepetition:
1356 if (id == CSSValueInfinite)
1357 validPrimitive = true;
1359 validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict);
1361 case CSSPropertyWebkitMarqueeSpeed:
1362 if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
1363 validPrimitive = true;
1365 validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict);
1368 case CSSPropertyWapMarqueeDir:
1369 if (id == CSSValueLtr || id == CSSValueRtl)
1370 validPrimitive = true;
1372 case CSSPropertyWapMarqueeStyle:
1373 if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate)
1374 validPrimitive = true;
1376 case CSSPropertyWapMarqueeLoop:
1377 if (id == CSSValueInfinite)
1378 validPrimitive = true;
1380 validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict);
1382 case CSSPropertyWapMarqueeSpeed:
1383 if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
1384 validPrimitive = true;
1386 validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict);
1389 case CSSPropertyWebkitUserDrag: // auto | none | element
1390 if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueElement)
1391 validPrimitive = true;
1393 case CSSPropertyWebkitUserModify: // read-only | read-write
1394 if (id == CSSValueReadOnly || id == CSSValueReadWrite || id == CSSValueReadWritePlaintextOnly)
1395 validPrimitive = true;
1397 case CSSPropertyWebkitUserSelect: // auto | none | text
1398 if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueText)
1399 validPrimitive = true;
1401 case CSSPropertyTextOverflow: // clip | ellipsis
1402 if (id == CSSValueClip || id == CSSValueEllipsis)
1403 validPrimitive = true;
1405 case CSSPropertyWebkitTransform:
1406 if (id == CSSValueNone)
1407 validPrimitive = true;
1409 PassRefPtr<CSSValue> val = parseTransform();
1411 addProperty(propId, val, important);
1417 case CSSPropertyWebkitTransformOrigin:
1418 case CSSPropertyWebkitTransformOriginX:
1419 case CSSPropertyWebkitTransformOriginY:
1420 case CSSPropertyWebkitTransformOriginZ: {
1421 RefPtr<CSSValue> val1;
1422 RefPtr<CSSValue> val2;
1423 RefPtr<CSSValue> val3;
1424 int propId1, propId2, propId3;
1425 if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
1426 addProperty(propId1, val1.release(), important);
1428 addProperty(propId2, val2.release(), important);
1430 addProperty(propId3, val3.release(), important);
1435 case CSSPropertyWebkitTransformStyle:
1436 if (value->id == CSSValueFlat || value->id == CSSValuePreserve3d)
1437 validPrimitive = true;
1439 case CSSPropertyWebkitBackfaceVisibility:
1440 if (value->id == CSSValueVisible || value->id == CSSValueHidden)
1441 validPrimitive = true;
1443 case CSSPropertyWebkitPerspective:
1444 if (id == CSSValueNone)
1445 validPrimitive = true;
1447 // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
1448 if (validUnit(value, FNumber | FLength | FNonNeg, m_strict)) {
1449 RefPtr<CSSValue> val = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1451 addProperty(propId, val.release(), important);
1458 case CSSPropertyWebkitPerspectiveOrigin:
1459 case CSSPropertyWebkitPerspectiveOriginX:
1460 case CSSPropertyWebkitPerspectiveOriginY: {
1461 RefPtr<CSSValue> val1;
1462 RefPtr<CSSValue> val2;
1463 int propId1, propId2;
1464 if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
1465 addProperty(propId1, val1.release(), important);
1467 addProperty(propId2, val2.release(), important);
1472 case CSSPropertyWebkitAnimationDelay:
1473 case CSSPropertyWebkitAnimationDirection:
1474 case CSSPropertyWebkitAnimationDuration:
1475 case CSSPropertyWebkitAnimationFillMode:
1476 case CSSPropertyWebkitAnimationName:
1477 case CSSPropertyWebkitAnimationPlayState:
1478 case CSSPropertyWebkitAnimationIterationCount:
1479 case CSSPropertyWebkitAnimationTimingFunction:
1480 case CSSPropertyWebkitTransitionDelay:
1481 case CSSPropertyWebkitTransitionDuration:
1482 case CSSPropertyWebkitTransitionTimingFunction:
1483 case CSSPropertyWebkitTransitionProperty: {
1484 RefPtr<CSSValue> val;
1485 if (parseAnimationProperty(propId, val)) {
1486 addProperty(propId, val.release(), important);
1491 case CSSPropertyWebkitMarginCollapse: {
1492 const int properties[2] = { CSSPropertyWebkitMarginTopCollapse,
1493 CSSPropertyWebkitMarginBottomCollapse };
1495 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
1496 if (!parseValue(properties[0], important))
1498 CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value();
1499 addProperty(properties[1], value, important);
1502 else if (num == 2) {
1503 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
1504 if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
1510 case CSSPropertyWebkitMarginTopCollapse:
1511 case CSSPropertyWebkitMarginBottomCollapse:
1512 if (id == CSSValueCollapse || id == CSSValueSeparate || id == CSSValueDiscard)
1513 validPrimitive = true;
1515 case CSSPropertyTextLineThroughMode:
1516 case CSSPropertyTextOverlineMode:
1517 case CSSPropertyTextUnderlineMode:
1518 if (id == CSSValueContinuous || id == CSSValueSkipWhiteSpace)
1519 validPrimitive = true;
1521 case CSSPropertyTextLineThroughStyle:
1522 case CSSPropertyTextOverlineStyle:
1523 case CSSPropertyTextUnderlineStyle:
1524 if (id == CSSValueNone || id == CSSValueSolid || id == CSSValueDouble ||
1525 id == CSSValueDashed || id == CSSValueDotDash || id == CSSValueDotDotDash ||
1527 validPrimitive = true;
1529 case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
1530 if (id == CSSValueAuto || id == CSSValueOptimizespeed || id == CSSValueOptimizelegibility
1531 || id == CSSValueGeometricprecision)
1532 validPrimitive = true;
1534 case CSSPropertyTextLineThroughWidth:
1535 case CSSPropertyTextOverlineWidth:
1536 case CSSPropertyTextUnderlineWidth:
1537 if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
1538 id == CSSValueMedium || id == CSSValueThick)
1539 validPrimitive = true;
1541 validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent, m_strict);
1543 case CSSPropertyResize: // none | both | horizontal | vertical | auto
1544 if (id == CSSValueNone || id == CSSValueBoth || id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
1545 validPrimitive = true;
1547 case CSSPropertyWebkitColumnCount:
1548 if (id == CSSValueAuto)
1549 validPrimitive = true;
1551 validPrimitive = !id && validUnit(value, FInteger | FNonNeg, false);
1553 case CSSPropertyWebkitColumnGap: // normal | <length>
1554 if (id == CSSValueNormal)
1555 validPrimitive = true;
1557 validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
1559 case CSSPropertyWebkitColumnSpan: // all | 1
1560 if (id == CSSValueAll)
1561 validPrimitive = true;
1563 validPrimitive = validUnit(value, FNumber | FNonNeg, m_strict) && value->fValue == 1;
1565 case CSSPropertyWebkitColumnWidth: // auto | <length>
1566 if (id == CSSValueAuto)
1567 validPrimitive = true;
1568 else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property.
1569 validPrimitive = validUnit(value, FLength, true);
1571 case CSSPropertyPointerEvents:
1572 // none | visiblePainted | visibleFill | visibleStroke | visible |
1573 // painted | fill | stroke | auto | all | inherit
1574 if (id == CSSValueVisible || id == CSSValueNone || id == CSSValueAll || id == CSSValueAuto ||
1575 (id >= CSSValueVisiblepainted && id <= CSSValueStroke))
1576 validPrimitive = true;
1579 // End of CSS3 properties
1581 // Apple specific properties. These will never be standardized and are purely to
1582 // support custom WebKit-based Apple applications.
1583 case CSSPropertyWebkitLineClamp:
1584 // When specifying number of lines, don't allow 0 as a valid value
1585 // When specifying either type of unit, require non-negative integers
1586 validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, false));
1588 case CSSPropertyWebkitTextSizeAdjust:
1589 if (id == CSSValueAuto || id == CSSValueNone)
1590 validPrimitive = true;
1592 case CSSPropertyWebkitRtlOrdering:
1593 if (id == CSSValueLogical || id == CSSValueVisual)
1594 validPrimitive = true;
1597 case CSSPropertyWebkitFontSizeDelta: // <length>
1598 validPrimitive = validUnit(value, FLength, m_strict);
1601 case CSSPropertyWebkitNbspMode: // normal | space
1602 if (id == CSSValueNormal || id == CSSValueSpace)
1603 validPrimitive = true;
1606 case CSSPropertyWebkitLineBreak: // normal | after-white-space
1607 if (id == CSSValueNormal || id == CSSValueAfterWhiteSpace)
1608 validPrimitive = true;
1611 case CSSPropertyWebkitMatchNearestMailBlockquoteColor: // normal | match
1612 if (id == CSSValueNormal || id == CSSValueMatch)
1613 validPrimitive = true;
1616 case CSSPropertyWebkitHighlight:
1617 if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
1618 validPrimitive = true;
1621 case CSSPropertyWebkitHyphens:
1622 if (id == CSSValueNone || id == CSSValueManual || id == CSSValueAuto)
1623 validPrimitive = true;
1626 case CSSPropertyWebkitHyphenateCharacter:
1627 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
1628 validPrimitive = true;
1631 case CSSPropertyWebkitHyphenateLocale:
1632 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
1633 validPrimitive = true;
1636 case CSSPropertyWebkitBorderFit:
1637 if (id == CSSValueBorder || id == CSSValueLines)
1638 validPrimitive = true;
1641 case CSSPropertyWebkitTextSecurity:
1642 // disc | circle | square | none | inherit
1643 if (id == CSSValueDisc || id == CSSValueCircle || id == CSSValueSquare|| id == CSSValueNone)
1644 validPrimitive = true;
1647 case CSSPropertyWebkitFontSmoothing:
1648 if (id == CSSValueAuto || id == CSSValueNone
1649 || id == CSSValueAntialiased || id == CSSValueSubpixelAntialiased)
1650 validPrimitive = true;
1653 #if ENABLE(DASHBOARD_SUPPORT)
1654 case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region>
1655 if (value->unit == CSSParserValue::Function || id == CSSValueNone)
1656 return parseDashboardRegions(propId, important);
1659 // End Apple-specific properties
1661 /* shorthand properties */
1662 case CSSPropertyBackground: {
1663 // Position must come before color in this array because a plain old "0" is a legal color
1664 // in quirks mode but it's usually the X coordinate of a position.
1665 // FIXME: Add CSSPropertyBackgroundSize to the shorthand.
1666 const int properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
1667 CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
1668 CSSPropertyBackgroundColor };
1669 return parseFillShorthand(propId, properties, 6, important);
1671 case CSSPropertyWebkitMask: {
1672 const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
1673 CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition,
1674 CSSPropertyWebkitMaskOrigin };
1675 return parseFillShorthand(propId, properties, 5, important);
1677 case CSSPropertyBorder:
1678 // [ 'border-width' || 'border-style' || <color> ] | inherit
1680 const int properties[3] = { CSSPropertyBorderWidth, CSSPropertyBorderStyle,
1681 CSSPropertyBorderColor };
1682 return parseShorthand(propId, properties, 3, important);
1684 case CSSPropertyBorderTop:
1685 // [ 'border-top-width' || 'border-style' || <color> ] | inherit
1687 const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle,
1688 CSSPropertyBorderTopColor};
1689 return parseShorthand(propId, properties, 3, important);
1691 case CSSPropertyBorderRight:
1692 // [ 'border-right-width' || 'border-style' || <color> ] | inherit
1694 const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle,
1695 CSSPropertyBorderRightColor };
1696 return parseShorthand(propId, properties, 3, important);
1698 case CSSPropertyBorderBottom:
1699 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
1701 const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle,
1702 CSSPropertyBorderBottomColor };
1703 return parseShorthand(propId, properties, 3, important);
1705 case CSSPropertyBorderLeft:
1706 // [ 'border-left-width' || 'border-style' || <color> ] | inherit
1708 const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle,
1709 CSSPropertyBorderLeftColor };
1710 return parseShorthand(propId, properties, 3, important);
1712 case CSSPropertyWebkitBorderStart:
1713 // [ '-webkit-border-start-width' || 'border-style' || <color> ] | inherit
1715 const int properties[3] = { CSSPropertyWebkitBorderStartWidth, CSSPropertyWebkitBorderStartStyle,
1716 CSSPropertyWebkitBorderStartColor };
1717 return parseShorthand(propId, properties, 3, important);
1719 case CSSPropertyWebkitBorderEnd:
1720 // [ '-webkit-border-end-width' || 'border-style' || <color> ] | inherit
1722 const int properties[3] = { CSSPropertyWebkitBorderEndWidth, CSSPropertyWebkitBorderEndStyle,
1723 CSSPropertyWebkitBorderEndColor };
1724 return parseShorthand(propId, properties, 3, important);
1726 case CSSPropertyOutline:
1727 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
1729 const int properties[3] = { CSSPropertyOutlineWidth, CSSPropertyOutlineStyle,
1730 CSSPropertyOutlineColor };
1731 return parseShorthand(propId, properties, 3, important);
1733 case CSSPropertyBorderColor:
1734 // <color>{1,4} | inherit
1736 const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor,
1737 CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor };
1738 return parse4Values(propId, properties, important);
1740 case CSSPropertyBorderWidth:
1741 // <border-width>{1,4} | inherit
1743 const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth,
1744 CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth };
1745 return parse4Values(propId, properties, important);
1747 case CSSPropertyBorderStyle:
1748 // <border-style>{1,4} | inherit
1750 const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle,
1751 CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle };
1752 return parse4Values(propId, properties, important);
1754 case CSSPropertyMargin:
1755 // <margin-width>{1,4} | inherit
1757 const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight,
1758 CSSPropertyMarginBottom, CSSPropertyMarginLeft };
1759 return parse4Values(propId, properties, important);
1761 case CSSPropertyPadding:
1762 // <padding-width>{1,4} | inherit
1764 const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight,
1765 CSSPropertyPaddingBottom, CSSPropertyPaddingLeft };
1766 return parse4Values(propId, properties, important);
1768 case CSSPropertyFont:
1769 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
1770 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
1771 if (id >= CSSValueCaption && id <= CSSValueStatusBar)
1772 validPrimitive = true;
1774 return parseFont(important);
1776 case CSSPropertyListStyle:
1778 const int properties[3] = { CSSPropertyListStyleType, CSSPropertyListStylePosition,
1779 CSSPropertyListStyleImage };
1780 return parseShorthand(propId, properties, 3, important);
1782 case CSSPropertyWebkitColumns: {
1783 const int properties[2] = { CSSPropertyWebkitColumnWidth, CSSPropertyWebkitColumnCount };
1784 return parseShorthand(propId, properties, 2, important);
1786 case CSSPropertyWebkitColumnRule: {
1787 const int properties[3] = { CSSPropertyWebkitColumnRuleWidth, CSSPropertyWebkitColumnRuleStyle,
1788 CSSPropertyWebkitColumnRuleColor };
1789 return parseShorthand(propId, properties, 3, important);
1791 case CSSPropertyWebkitTextStroke: {
1792 const int properties[2] = { CSSPropertyWebkitTextStrokeWidth, CSSPropertyWebkitTextStrokeColor };
1793 return parseShorthand(propId, properties, 2, important);
1795 case CSSPropertyWebkitAnimation:
1796 return parseAnimationShorthand(important);
1797 case CSSPropertyWebkitTransition:
1798 return parseTransitionShorthand(important);
1799 case CSSPropertyInvalid:
1801 case CSSPropertyPage:
1802 return parsePage(propId, important);
1803 case CSSPropertyFontStretch:
1804 case CSSPropertyTextLineThrough:
1805 case CSSPropertyTextOverline:
1806 case CSSPropertyTextUnderline:
1807 case CSSPropertyWebkitVariableDeclarationBlock:
1811 case CSSPropertyWapInputFormat:
1812 validPrimitive = true;
1814 case CSSPropertyWapInputRequired:
1815 parsedValue = parseWCSSInputProperty();
1819 #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
1820 case CSSPropertyWebkitTapHighlightColor:
1821 parsedValue = parseColor();
1823 m_valueList->next();
1829 return parseSVGValue(propId, important);
1833 if (validPrimitive) {
1835 parsedValue = CSSPrimitiveValue::createIdentifier(id);
1836 else if (value->unit == CSSPrimitiveValue::CSS_STRING)
1837 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
1838 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1839 parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
1840 else if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS)
1841 parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
1842 else if (value->unit >= CSSParserValue::Q_EMS)
1843 parsedValue = CSSQuirkPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_EMS);
1844 m_valueList->next();
1847 if (!m_valueList->current() || inShorthand()) {
1848 addProperty(propId, parsedValue.release(), important);
1856 PassRefPtr<CSSValue> CSSParser::parseWCSSInputProperty()
1858 RefPtr<CSSValue> parsedValue = 0;
1859 CSSParserValue* value = m_valueList->current();
1860 String inputProperty;
1861 if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT)
1862 inputProperty = String(value->string);
1864 if (!inputProperty.isEmpty())
1865 parsedValue = CSSPrimitiveValue::create(inputProperty, CSSPrimitiveValue::CSS_STRING);
1867 while (m_valueList->next()) {
1868 // pass all other values, if any. If we don't do this,
1869 // the parser will think that it's not done and won't process this property
1876 void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
1879 if (lval->isValueList())
1880 static_cast<CSSValueList*>(lval.get())->append(rval);
1882 PassRefPtr<CSSValue> oldlVal(lval.release());
1883 PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
1884 list->append(oldlVal);
1893 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue)
1895 if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox || parserValue->id == CSSValueWebkitText) {
1896 cssValue = CSSPrimitiveValue::createIdentifier(parserValue->id);
1902 const int cMaxFillProperties = 9;
1904 bool CSSParser::parseFillShorthand(int propId, const int* properties, int numProperties, bool important)
1906 ASSERT(numProperties <= cMaxFillProperties);
1907 if (numProperties > cMaxFillProperties)
1910 ShorthandScope scope(this, propId);
1912 bool parsedProperty[cMaxFillProperties] = { false };
1913 RefPtr<CSSValue> values[cMaxFillProperties];
1914 RefPtr<CSSValue> clipValue;
1915 RefPtr<CSSValue> positionYValue;
1916 RefPtr<CSSValue> repeatYValue;
1919 while (m_valueList->current()) {
1920 CSSParserValue* val = m_valueList->current();
1921 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
1922 // We hit the end. Fill in all remaining values with the initial value.
1923 m_valueList->next();
1924 for (i = 0; i < numProperties; ++i) {
1925 if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
1926 // Color is not allowed except as the last item in a list for backgrounds.
1927 // Reject the entire property.
1930 if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
1931 addFillValue(values[i], CSSInitialValue::createImplicit());
1932 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1933 addFillValue(positionYValue, CSSInitialValue::createImplicit());
1934 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1935 addFillValue(repeatYValue, CSSInitialValue::createImplicit());
1936 if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
1937 // If background-origin wasn't present, then reset background-clip also.
1938 addFillValue(clipValue, CSSInitialValue::createImplicit());
1941 parsedProperty[i] = false;
1943 if (!m_valueList->current())
1948 for (i = 0; !found && i < numProperties; ++i) {
1949 if (!parsedProperty[i]) {
1950 RefPtr<CSSValue> val1;
1951 RefPtr<CSSValue> val2;
1952 int propId1, propId2;
1953 CSSParserValue* parserValue = m_valueList->current();
1954 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
1955 parsedProperty[i] = found = true;
1956 addFillValue(values[i], val1.release());
1957 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1958 addFillValue(positionYValue, val2.release());
1959 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1960 addFillValue(repeatYValue, val2.release());
1961 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
1962 // Reparse the value as a clip, and see if we succeed.
1963 if (parseBackgroundClip(parserValue, val1))
1964 addFillValue(clipValue, val1.release()); // The property parsed successfully.
1966 addFillValue(clipValue, CSSInitialValue::createImplicit()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
1972 // if we didn't find at least one match, this is an
1973 // invalid shorthand and we have to ignore it
1978 // Fill in any remaining properties with the initial value.
1979 for (i = 0; i < numProperties; ++i) {
1980 if (!parsedProperty[i]) {
1981 addFillValue(values[i], CSSInitialValue::createImplicit());
1982 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1983 addFillValue(positionYValue, CSSInitialValue::createImplicit());
1984 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1985 addFillValue(repeatYValue, CSSInitialValue::createImplicit());
1986 if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
1987 // If background-origin wasn't present, then reset background-clip also.
1988 addFillValue(clipValue, CSSInitialValue::createImplicit());
1993 // Now add all of the properties we found.
1994 for (i = 0; i < numProperties; i++) {
1995 if (properties[i] == CSSPropertyBackgroundPosition) {
1996 addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
1997 // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
1998 addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
1999 } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
2000 addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
2001 // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
2002 addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
2003 } else if (properties[i] == CSSPropertyBackgroundRepeat) {
2004 addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
2005 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
2006 addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
2007 } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
2008 addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
2009 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
2010 addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
2012 addProperty(properties[i], values[i].release(), important);
2014 // Add in clip values when we hit the corresponding origin property.
2015 if (properties[i] == CSSPropertyBackgroundOrigin)
2016 addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
2017 else if (properties[i] == CSSPropertyWebkitMaskOrigin)
2018 addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
2024 void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
2027 if (lval->isValueList())
2028 static_cast<CSSValueList*>(lval.get())->append(rval);
2030 PassRefPtr<CSSValue> oldVal(lval.release());
2031 PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
2032 list->append(oldVal);
2041 bool CSSParser::parseAnimationShorthand(bool important)
2043 const int properties[] = { CSSPropertyWebkitAnimationName,
2044 CSSPropertyWebkitAnimationDuration,
2045 CSSPropertyWebkitAnimationTimingFunction,
2046 CSSPropertyWebkitAnimationDelay,
2047 CSSPropertyWebkitAnimationIterationCount,
2048 CSSPropertyWebkitAnimationDirection,
2049 CSSPropertyWebkitAnimationFillMode };
2050 const int numProperties = sizeof(properties) / sizeof(properties[0]);
2052 ShorthandScope scope(this, CSSPropertyWebkitAnimation);
2054 bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
2055 RefPtr<CSSValue> values[numProperties];
2058 while (m_valueList->current()) {
2059 CSSParserValue* val = m_valueList->current();
2060 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
2061 // We hit the end. Fill in all remaining values with the initial value.
2062 m_valueList->next();
2063 for (i = 0; i < numProperties; ++i) {
2064 if (!parsedProperty[i])
2065 addAnimationValue(values[i], CSSInitialValue::createImplicit());
2066 parsedProperty[i] = false;
2068 if (!m_valueList->current())
2073 for (i = 0; !found && i < numProperties; ++i) {
2074 if (!parsedProperty[i]) {
2075 RefPtr<CSSValue> val;
2076 if (parseAnimationProperty(properties[i], val)) {
2077 parsedProperty[i] = found = true;
2078 addAnimationValue(values[i], val.release());
2083 // if we didn't find at least one match, this is an
2084 // invalid shorthand and we have to ignore it
2089 // Fill in any remaining properties with the initial value.
2090 for (i = 0; i < numProperties; ++i) {
2091 if (!parsedProperty[i])
2092 addAnimationValue(values[i], CSSInitialValue::createImplicit());
2095 // Now add all of the properties we found.
2096 for (i = 0; i < numProperties; i++)
2097 addProperty(properties[i], values[i].release(), important);
2102 bool CSSParser::parseTransitionShorthand(bool important)
2104 const int properties[] = { CSSPropertyWebkitTransitionProperty,
2105 CSSPropertyWebkitTransitionDuration,
2106 CSSPropertyWebkitTransitionTimingFunction,
2107 CSSPropertyWebkitTransitionDelay };
2108 const int numProperties = sizeof(properties) / sizeof(properties[0]);
2110 ShorthandScope scope(this, CSSPropertyWebkitTransition);
2112 bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
2113 RefPtr<CSSValue> values[numProperties];
2116 while (m_valueList->current()) {
2117 CSSParserValue* val = m_valueList->current();
2118 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
2119 // We hit the end. Fill in all remaining values with the initial value.
2120 m_valueList->next();
2121 for (i = 0; i < numProperties; ++i) {
2122 if (!parsedProperty[i])
2123 addAnimationValue(values[i], CSSInitialValue::createImplicit());
2124 parsedProperty[i] = false;
2126 if (!m_valueList->current())
2131 for (i = 0; !found && i < numProperties; ++i) {
2132 if (!parsedProperty[i]) {
2133 RefPtr<CSSValue> val;
2134 if (parseAnimationProperty(properties[i], val)) {
2135 parsedProperty[i] = found = true;
2136 addAnimationValue(values[i], val.release());
2141 // if we didn't find at least one match, this is an
2142 // invalid shorthand and we have to ignore it
2147 // Fill in any remaining properties with the initial value.
2148 for (i = 0; i < numProperties; ++i) {
2149 if (!parsedProperty[i])
2150 addAnimationValue(values[i], CSSInitialValue::createImplicit());
2153 // Now add all of the properties we found.
2154 for (i = 0; i < numProperties; i++)
2155 addProperty(properties[i], values[i].release(), important);
2160 bool CSSParser::parseShorthand(int propId, const int *properties, int numProperties, bool important)
2162 // We try to match as many properties as possible
2163 // We set up an array of booleans to mark which property has been found,
2164 // and we try to search for properties until it makes no longer any sense.
2165 ShorthandScope scope(this, propId);
2168 bool fnd[6]; // Trust me ;)
2169 for (int i = 0; i < numProperties; i++)
2172 while (m_valueList->current()) {
2174 for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
2175 if (!fnd[propIndex]) {
2176 if (parseValue(properties[propIndex], important))
2177 fnd[propIndex] = found = true;
2181 // if we didn't find at least one match, this is an
2182 // invalid shorthand and we have to ignore it
2187 // Fill in any remaining properties with the initial value.
2188 m_implicitShorthand = true;
2189 for (int i = 0; i < numProperties; ++i) {
2191 addProperty(properties[i], CSSInitialValue::createImplicit(), important);
2193 m_implicitShorthand = false;
2198 bool CSSParser::parse4Values(int propId, const int *properties, bool important)
2200 /* From the CSS 2 specs, 8.3
2201 * If there is only one value, it applies to all sides. If there are two values, the top and
2202 * bottom margins are set to the first value and the right and left margins are set to the second.
2203 * If there are three values, the top is set to the first value, the left and right are set to the
2204 * second, and the bottom is set to the third. If there are four values, they apply to the top,
2205 * right, bottom, and left, respectively.
2208 int num = inShorthand() ? 1 : m_valueList->size();
2210 ShorthandScope scope(this, propId);
2212 // the order is top, right, bottom, left
2215 if (!parseValue(properties[0], important))
2217 CSSValue *value = m_parsedProperties[m_numParsedProperties-1]->value();
2218 m_implicitShorthand = true;
2219 addProperty(properties[1], value, important);
2220 addProperty(properties[2], value, important);
2221 addProperty(properties[3], value, important);
2222 m_implicitShorthand = false;
2226 if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
2228 CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value();
2229 m_implicitShorthand = true;
2230 addProperty(properties[2], value, important);
2231 value = m_parsedProperties[m_numParsedProperties-2]->value();
2232 addProperty(properties[3], value, important);
2233 m_implicitShorthand = false;
2237 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
2239 CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value();
2240 m_implicitShorthand = true;
2241 addProperty(properties[3], value, important);
2242 m_implicitShorthand = false;
2246 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
2247 !parseValue(properties[2], important) || !parseValue(properties[3], important))
2259 // auto | <identifier>
2260 bool CSSParser::parsePage(int propId, bool important)
2262 ASSERT(propId == CSSPropertyPage);
2264 if (m_valueList->size() != 1)
2267 CSSParserValue* value = m_valueList->current();
2271 if (value->id == CSSValueAuto) {
2272 addProperty(propId, CSSPrimitiveValue::createIdentifier(value->id), important);
2274 } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
2275 addProperty(propId, CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_STRING), important);
2281 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
2282 bool CSSParser::parseSize(int propId, bool important)
2284 ASSERT(propId == CSSPropertySize);
2286 if (m_valueList->size() > 2)
2289 CSSParserValue* value = m_valueList->current();
2293 RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
2296 SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
2297 if (paramType == None)
2300 // Second parameter, if any.
2301 value = m_valueList->next();
2303 paramType = parseSizeParameter(parsedValues.get(), value, paramType);
2304 if (paramType == None)
2308 addProperty(propId, parsedValues.release(), important);
2312 CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
2314 switch (value->id) {
2316 if (prevParamType == None) {
2317 parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id));
2321 case CSSValueLandscape:
2322 case CSSValuePortrait:
2323 if (prevParamType == None || prevParamType == PageSize) {
2324 parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id));
2333 case CSSValueLedger:
2335 case CSSValueLetter:
2336 if (prevParamType == None || prevParamType == Orientation) {
2337 // Normalize to Page Size then Orientation order by prepending.
2338 // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (CSSStyleSelector::applyPageSizeProperty).
2339 parsedValues->prepend(CSSPrimitiveValue::createIdentifier(value->id));
2344 if (validUnit(value, FLength | FNonNeg, m_strict) && (prevParamType == None || prevParamType == Length)) {
2345 parsedValues->append(CSSPrimitiveValue::create(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
2354 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
2355 // in CSS 2.1 this got somewhat reduced:
2356 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
2357 bool CSSParser::parseContent(int propId, bool important)
2359 RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
2361 while (CSSParserValue* val = m_valueList->current()) {
2362 RefPtr<CSSValue> parsedValue;
2363 if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
2365 // FIXME: The completeURL call should be done when using the CSSImageValue,
2366 // not when creating it.
2367 parsedValue = CSSImageValue::create(m_styleSheet->completeURL(val->string));
2368 } else if (val->unit == CSSParserValue::Function) {
2369 // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
2370 CSSParserValueList* args = val->function->args;
2373 if (equalIgnoringCase(val->function->name, "attr(")) {
2374 parsedValue = parseAttr(args);
2377 } else if (equalIgnoringCase(val->function->name, "counter(")) {
2378 parsedValue = parseCounterContent(args, false);
2381 } else if (equalIgnoringCase(val->function->name, "counters(")) {
2382 parsedValue = parseCounterContent(args, true);
2385 } else if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) {
2386 if (!parseGradient(parsedValue))
2388 } else if (equalIgnoringCase(val->function->name, "-webkit-canvas(")) {
2389 if (!parseCanvas(parsedValue))
2393 } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
2398 // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
2399 } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
2400 parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
2404 values->append(parsedValue.release());
2405 m_valueList->next();
2408 if (values->length()) {
2409 addProperty(propId, values.release(), important);
2410 m_valueList->next();
2417 PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args)
2419 if (args->size() != 1)
2422 CSSParserValue* a = args->current();
2424 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
2427 String attrName = a->string;
2428 // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
2429 // But HTML attribute names can't have those characters, and we should not
2430 // even parse them inside attr().
2431 if (attrName[0] == '-')
2434 if (document() && document()->isHTMLDocument())
2435 attrName = attrName.lower();
2437 return CSSPrimitiveValue::create(attrName, CSSPrimitiveValue::CSS_ATTR);
2440 PassRefPtr<CSSValue> CSSParser::parseBackgroundColor()
2442 int id = m_valueList->current()->id;
2443 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
2444 (id >= CSSValueGrey && id < CSSValueWebkitText && !m_strict))
2445 return CSSPrimitiveValue::createIdentifier(id);
2446 return parseColor();
2449 bool CSSParser::parseFillImage(RefPtr<CSSValue>& value)
2451 if (m_valueList->current()->id == CSSValueNone) {
2452 value = CSSImageValue::create();
2455 if (m_valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
2456 // FIXME: The completeURL call should be done when using the CSSImageValue,
2457 // not when creating it.
2459 value = CSSImageValue::create(m_styleSheet->completeURL(m_valueList->current()->string));
2463 if (m_valueList->current()->unit == CSSParserValue::Function) {
2464 if (equalIgnoringCase(m_valueList->current()->function->name, "-webkit-gradient("))
2465 return parseGradient(value);
2466 if (equalIgnoringCase(m_valueList->current()->function->name, "-webkit-canvas("))
2467 return parseCanvas(value);
2473 PassRefPtr<CSSValue> CSSParser::parseFillPositionXY(bool& xFound, bool& yFound)
2475 int id = m_valueList->current()->id;
2476 if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
2478 if (id == CSSValueLeft || id == CSSValueRight) {
2482 if (id == CSSValueRight)
2485 else if (id == CSSValueTop || id == CSSValueBottom) {
2489 if (id == CSSValueBottom)
2492 else if (id == CSSValueCenter)
2493 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
2495 return CSSPrimitiveValue::create(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2497 if (validUnit(m_valueList->current(), FPercent | FLength, m_strict))
2498 return CSSPrimitiveValue::create(m_valueList->current()->fValue,
2499 (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit);
2504 void CSSParser::parseFillPosition(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
2506 CSSParserValue* value = m_valueList->current();
2508 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
2509 bool value1IsX = false, value1IsY = false;
2510 value1 = parseFillPositionXY(value1IsX, value1IsY);
2514 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
2515 // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the
2516 // value was explicitly specified for our property.
2517 value = m_valueList->next();
2519 // First check for the comma. If so, we are finished parsing this value or value pair.
2520 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
2523 bool value2IsX = false, value2IsY = false;
2525 value2 = parseFillPositionXY(value2IsX, value2IsY);
2527 m_valueList->next();
2529 if (!inShorthand()) {
2537 // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
2538 // is simply 50%. This is our default.
2539 // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
2540 // For left/right/center, the default of 50% in the y is still correct.
2541 value2 = CSSPrimitiveValue::create(50, CSSPrimitiveValue::CSS_PERCENTAGE);
2543 if (value1IsY || value2IsX)
2544 value1.swap(value2);
2547 void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
2549 CSSParserValue* value = m_valueList->current();
2551 int id = m_valueList->current()->id;
2552 if (id == CSSValueRepeatX) {
2553 m_implicitShorthand = true;
2554 value1 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat);
2555 value2 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat);
2556 m_valueList->next();
2559 if (id == CSSValueRepeatY) {
2560 m_implicitShorthand = true;
2561 value1 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat);
2562 value2 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat);
2563 m_valueList->next();
2566 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
2567 value1 = CSSPrimitiveValue::createIdentifier(id);
2573 value = m_valueList->next();
2575 // First check for the comma. If so, we are finished parsing this value or value pair.
2576 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
2580 id = m_valueList->current()->id;
2582 if (value && (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)) {
2583 value2 = CSSPrimitiveValue::createIdentifier(id);
2584 m_valueList->next();
2586 // If only one value was specified, value2 is the same as value1.
2587 m_implicitShorthand = true;
2588 value2 = CSSPrimitiveValue::createIdentifier(static_cast<CSSPrimitiveValue*>(value1.get())->getIdent());
2592 PassRefPtr<CSSValue> CSSParser::parseFillSize(int propId, bool& allowComma)
2595 CSSParserValue* value = m_valueList->current();
2597 if (value->id == CSSValueContain || value->id == CSSValueCover)
2598 return CSSPrimitiveValue::createIdentifier(value->id);
2600 RefPtr<CSSPrimitiveValue> parsedValue1;
2602 if (value->id == CSSValueAuto)
2603 parsedValue1 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN);
2605 if (!validUnit(value, FLength | FPercent, m_strict))
2607 parsedValue1 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2610 CSSPropertyID property = static_cast<CSSPropertyID>(propId);
2611 RefPtr<CSSPrimitiveValue> parsedValue2;
2612 if ((value = m_valueList->next())) {
2613 if (value->id == CSSValueAuto)
2614 parsedValue2 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN);
2615 else if (value->unit == CSSParserValue::Operator && value->iValue == ',')
2618 if (!validUnit(value, FLength | FPercent, m_strict))
2620 parsedValue2 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2623 if (!parsedValue2) {
2624 if (property == CSSPropertyWebkitBackgroundSize || property == CSSPropertyWebkitMaskSize)
2625 parsedValue2 = parsedValue1;
2627 parsedValue2 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN);
2630 return CSSPrimitiveValue::create(Pair::create(parsedValue1.release(), parsedValue2.release()));
2633 bool CSSParser::parseFillProperty(int propId, int& propId1, int& propId2,
2634 RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
2636 RefPtr<CSSValueList> values;
2637 RefPtr<CSSValueList> values2;
2638 CSSParserValue* val;
2639 RefPtr<CSSValue> value;
2640 RefPtr<CSSValue> value2;
2642 bool allowComma = false;
2644 retValue1 = retValue2 = 0;
2647 if (propId == CSSPropertyBackgroundPosition) {
2648 propId1 = CSSPropertyBackgroundPositionX;
2649 propId2 = CSSPropertyBackgroundPositionY;
2650 } else if (propId == CSSPropertyWebkitMaskPosition) {
2651 propId1 = CSSPropertyWebkitMaskPositionX;
2652 propId2 = CSSPropertyWebkitMaskPositionY;
2653 } else if (propId == CSSPropertyBackgroundRepeat) {
2654 propId1 = CSSPropertyBackgroundRepeatX;
2655 propId2 = CSSPropertyBackgroundRepeatY;
2656 } else if (propId == CSSPropertyWebkitMaskRepeat) {
2657 propId1 = CSSPropertyWebkitMaskRepeatX;
2658 propId2 = CSSPropertyWebkitMaskRepeatY;
2661 while ((val = m_valueList->current())) {
2662 RefPtr<CSSValue> currValue;
2663 RefPtr<CSSValue> currValue2;
2666 if (val->unit != CSSParserValue::Operator || val->iValue != ',')
2668 m_valueList->next();
2673 case CSSPropertyBackgroundColor:
2674 currValue = parseBackgroundColor();
2676 m_valueList->next();
2678 case CSSPropertyBackgroundAttachment:
2679 case CSSPropertyWebkitMaskAttachment:
2680 if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
2681 currValue = CSSPrimitiveValue::createIdentifier(val->id);
2682 m_valueList->next();
2685 case CSSPropertyBackgroundImage:
2686 case CSSPropertyWebkitMaskImage:
2687 if (parseFillImage(currValue))
2688 m_valueList->next();
2690 case CSSPropertyWebkitBackgroundClip:
2691 case CSSPropertyWebkitBackgroundOrigin:
2692 case CSSPropertyWebkitMaskClip:
2693 case CSSPropertyWebkitMaskOrigin:
2694 // The first three values here are deprecated and do not apply to the version of the property that has
2695 // the -webkit- prefix removed.
2696 if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
2697 val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
2698 ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
2699 (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
2700 currValue = CSSPrimitiveValue::createIdentifier(val->id);
2701 m_valueList->next();
2704 case CSSPropertyBackgroundClip:
2705 if (parseBackgroundClip(val, currValue))
2706 m_valueList->next();
2708 case CSSPropertyBackgroundOrigin:
2709 if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
2710 currValue = CSSPrimitiveValue::createIdentifier(val->id);
2711 m_valueList->next();
2714 case CSSPropertyBackgroundPosition:
2715 case CSSPropertyWebkitMaskPosition:
2716 parseFillPosition(currValue, currValue2);
2717 // parseFillPosition advances the m_valueList pointer
2719 case CSSPropertyBackgroundPositionX:
2720 case CSSPropertyWebkitMaskPositionX: {
2721 bool xFound = false, yFound = true;
2722 currValue = parseFillPositionXY(xFound, yFound);
2724 m_valueList->next();
2727 case CSSPropertyBackgroundPositionY:
2728 case CSSPropertyWebkitMaskPositionY: {
2729 bool xFound = true, yFound = false;
2730 currValue = parseFillPositionXY(xFound, yFound);
2732 m_valueList->next();
2735 case CSSPropertyWebkitBackgroundComposite:
2736 case CSSPropertyWebkitMaskComposite:
2737 if ((val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) || val->id == CSSValueHighlight) {
2738 currValue = CSSPrimitiveValue::createIdentifier(val->id);
2739 m_valueList->next();
2742 case CSSPropertyBackgroundRepeat:
2743 case CSSPropertyWebkitMaskRepeat:
2744 parseFillRepeat(currValue, currValue2);
2745 // parseFillRepeat advances the m_valueList pointer
2747 case CSSPropertyBackgroundSize:
2748 case CSSPropertyWebkitBackgroundSize:
2749 case CSSPropertyWebkitMaskSize: {
2750 currValue = parseFillSize(propId, allowComma);
2752 m_valueList->next();
2759 if (value && !values) {
2760 values = CSSValueList::createCommaSeparated();
2761 values->append(value.release());
2764 if (value2 && !values2) {
2765 values2 = CSSValueList::createCommaSeparated();
2766 values2->append(value2.release());
2770 values->append(currValue.release());
2772 value = currValue.release();
2775 values2->append(currValue2.release());
2777 value2 = currValue2.release();
2781 // When parsing any fill shorthand property, we let it handle building up the lists for all
2787 if (values && values->length()) {
2788 retValue1 = values.release();
2789 if (values2 && values2->length())
2790 retValue2 = values2.release();
2794 retValue1 = value.release();
2795 retValue2 = value2.release();
2801 PassRefPtr<CSSValue> CSSParser::parseAnimationDelay()
2803 CSSParserValue* value = m_valueList->current();
2804 if (validUnit(value, FTime, m_strict))
2805 return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2809 PassRefPtr<CSSValue> CSSParser::parseAnimationDirection()
2811 CSSParserValue* value = m_valueList->current();
2812 if (value->id == CSSValueNormal || value->id == CSSValueAlternate)
2813 return CSSPrimitiveValue::createIdentifier(value->id);
2817 PassRefPtr<CSSValue> CSSParser::parseAnimationDuration()
2819 CSSParserValue* value = m_valueList->current();
2820 if (validUnit(value, FTime | FNonNeg, m_strict))
2821 return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2825 PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode()
2827 CSSParserValue* value = m_valueList->current();
2828 if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
2829 return CSSPrimitiveValue::createIdentifier(value->id);
2833 PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount()
2835 CSSParserValue* value = m_valueList->current();
2836 if (value->id == CSSValueInfinite)
2837 return CSSPrimitiveValue::createIdentifier(value->id);
2838 if (validUnit(value, FInteger | FNonNeg, m_strict))
2839 return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2843 PassRefPtr<CSSValue> CSSParser::parseAnimationName()
2845 CSSParserValue* value = m_valueList->current();
2846 if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
2847 if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value->string, "none"))) {
2848 return CSSPrimitiveValue::createIdentifier(CSSValueNone);
2850 return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_STRING);
2856 PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState()
2858 CSSParserValue* value = m_valueList->current();
2859 if (value->id == CSSValueRunning || value->id == CSSValuePaused)
2860 return CSSPrimitiveValue::createIdentifier(value->id);
2864 PassRefPtr<CSSValue> CSSParser::parseAnimationProperty()
2866 CSSParserValue* value = m_valueList->current();
2867 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
2869 int result = cssPropertyID(value->string);
2871 return CSSPrimitiveValue::createIdentifier(result);
2872 if (equalIgnoringCase(value->string, "all"))
2873 return CSSPrimitiveValue::createIdentifier(CSSValueAll);
2874 if (equalIgnoringCase(value->string, "none"))
2875 return CSSPrimitiveValue::createIdentifier(CSSValueNone);
2879 void CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
2881 parseFillPosition(value1, value2);
2884 if (m_valueList->current() && validUnit(m_valueList->current(), FLength, m_strict))
2885 value3 = CSSPrimitiveValue::create(m_valueList->current()->fValue,
2886 (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit);
2888 m_valueList->next();
2891 bool CSSParser::parseTimingFunctionValue(CSSParserValueList*& args, double& result)
2893 CSSParserValue* v = args->current();
2894 if (!validUnit(v, FNumber, m_strict))
2897 if (result < 0 || result > 1.0)
2901 // The last number in the function has no comma after it, so we're done.
2903 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
2909 PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction()
2911 CSSParserValue* value = m_valueList->current();
2912 if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut || value->id == CSSValueEaseInOut)
2913 return CSSPrimitiveValue::createIdentifier(value->id);
2915 // We must be a function.
2916 if (value->unit != CSSParserValue::Function)
2919 // The only timing function we accept for now is a cubic bezier function. 4 points must be specified.
2920 CSSParserValueList* args = value->function->args;
2921 if (!equalIgnoringCase(value->function->name, "cubic-bezier(") || !args || args->size() != 7)
2924 // There are two points specified. The values must be between 0 and 1.
2925 double x1, y1, x2, y2;
2927 if (!parseTimingFunctionValue(args, x1))
2929 if (!parseTimingFunctionValue(args, y1))
2931 if (!parseTimingFunctionValue(args, x2))
2933 if (!parseTimingFunctionValue(args, y2))
2936 return CSSTimingFunctionValue::create(x1, y1, x2, y2);
2939 bool CSSParser::parseAnimationProperty(int propId, RefPtr<CSSValue>& result)
2941 RefPtr<CSSValueList> values;
2942 CSSParserValue* val;
2943 RefPtr<CSSValue> value;
2944 bool allowComma = false;
2948 while ((val = m_valueList->current())) {
2949 RefPtr<CSSValue> currValue;
2951 if (val->unit != CSSParserValue::Operator || val->iValue != ',')
2953 m_valueList->next();
2958 case CSSPropertyWebkitAnimationDelay:
2959 case CSSPropertyWebkitTransitionDelay:
2960 currValue = parseAnimationDelay();
2962 m_valueList->next();
2964 case CSSPropertyWebkitAnimationDirection:
2965 currValue = parseAnimationDirection();
2967 m_valueList->next();
2969 case CSSPropertyWebkitAnimationDuration:
2970 case CSSPropertyWebkitTransitionDuration:
2971 currValue = parseAnimationDuration();
2973 m_valueList->next();
2975 case CSSPropertyWebkitAnimationFillMode:
2976 currValue = parseAnimationFillMode();
2978 m_valueList->next();
2980 case CSSPropertyWebkitAnimationIterationCount:
2981 currValue = parseAnimationIterationCount();
2983 m_valueList->next();
2985 case CSSPropertyWebkitAnimationName:
2986 currValue = parseAnimationName();
2988 m_valueList->next();
2990 case CSSPropertyWebkitAnimationPlayState:
2991 currValue = parseAnimationPlayState();
2993 m_valueList->next();
2995 case CSSPropertyWebkitTransitionProperty:
2996 currValue = parseAnimationProperty();
2998 m_valueList->next();
3000 case CSSPropertyWebkitAnimationTimingFunction:
3001 case CSSPropertyWebkitTransitionTimingFunction:
3002 currValue = parseAnimationTimingFunction();
3004 m_valueList->next();
3011 if (value && !values) {
3012 values = CSSValueList::createCommaSeparated();
3013 values->append(value.release());
3017 values->append(currValue.release());
3019 value = currValue.release();
3024 // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
3030 if (values && values->length()) {
3031 result = values.release();
3035 result = value.release();
3043 #if ENABLE(DASHBOARD_SUPPORT)
3045 #define DASHBOARD_REGION_NUM_PARAMETERS 6
3046 #define DASHBOARD_REGION_SHORT_NUM_PARAMETERS 2
3048 static CSSParserValue* skipCommaInDashboardRegion(CSSParserValueList *args)
3050 if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) ||
3051 args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
3052 CSSParserValue* current = args->current();
3053 if (current->unit == CSSParserValue::Operator && current->iValue == ',')
3054 return args->next();
3056 return args->current();
3059 bool CSSParser::parseDashboardRegions(int propId, bool important)
3063 CSSParserValue* value = m_valueList->current();
3065 if (value->id == CSSValueNone) {
3066 if (m_valueList->next())
3068 addProperty(propId, CSSPrimitiveValue::createIdentifier(value->id), important);
3072 RefPtr<DashboardRegion> firstRegion = DashboardRegion::create();
3073 DashboardRegion* region = 0;
3077 region = firstRegion.get();
3079 RefPtr<DashboardRegion> nextRegion = DashboardRegion::create();
3080 region->m_next = nextRegion;
3081 region = nextRegion.get();
3084 if (value->unit != CSSParserValue::Function) {
3089 // Commas count as values, so allow:
3090 // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
3091 // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
3093 // dashboard-region(label, type) or dashboard-region(label type)
3094 // dashboard-region(label, type) or dashboard-region(label type)
3095 CSSParserValueList* args = value->function->args;
3096 if (!equalIgnoringCase(value->function->name, "dashboard-region(") || !args) {
3101 int numArgs = args->size();
3102 if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) &&
3103 (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))) {
3108 // First arg is a label.
3109 CSSParserValue* arg = args->current();
3110 if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
3115 region->m_label = arg->string;
3117 // Second arg is a type.
3119 arg = skipCommaInDashboardRegion(args);
3120 if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
3125 if (equalIgnoringCase(arg->string, "circle"))
3126 region->m_isCircle = true;
3127 else if (equalIgnoringCase(arg->string, "rectangle"))
3128 region->m_isRectangle = true;
3134 region->m_geometryType = arg->string;
3136 if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
3137 // This originally used CSSValueInvalid by accident. It might be more logical to use something else.
3138 RefPtr<CSSPrimitiveValue> amount = CSSPrimitiveValue::createIdentifier(CSSValueInvalid);
3140 region->setTop(amount);
3141 region->setRight(amount);
3142 region->setBottom(amount);
3143 region->setLeft(amount);
3145 // Next four arguments must be offset numbers
3147 for (i = 0; i < 4; i++) {
3149 arg = skipCommaInDashboardRegion(args);
3151 valid = arg->id == CSSValueAuto || validUnit(arg, FLength, m_strict);
3155 RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ?
3156 CSSPrimitiveValue::createIdentifier(CSSValueAuto) :
3157 CSSPrimitiveValue::create(arg->fValue, (CSSPrimitiveValue::UnitTypes) arg->unit);
3160 region->setTop(amount);
3162 region->setRight(amount);
3164 region->setBottom(amount);
3166 region->setLeft(amount);
3173 value = m_valueList->next();
3177 addProperty(propId, CSSPrimitiveValue::create(firstRegion.release()), important);
3182 #endif /* ENABLE(DASHBOARD_SUPPORT) */
3184 PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
3186 unsigned numArgs = args->size();
3187 if (counters && numArgs != 3 && numArgs != 5)
3189 if (!counters && numArgs != 1 && numArgs != 3)
3192 CSSParserValue* i = args->current();
3193 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
3195 RefPtr<CSSPrimitiveValue> identifier = CSSPrimitiveValue::create(i->string, CSSPrimitiveValue::CSS_STRING);
3197 RefPtr<CSSPrimitiveValue> separator;
3199 separator = CSSPrimitiveValue::create(String(), CSSPrimitiveValue::CSS_STRING);
3202 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
3206 if (i->unit != CSSPrimitiveValue::CSS_STRING)
3209 separator = CSSPrimitiveValue::create(i->string, (CSSPrimitiveValue::UnitTypes) i->unit);
3212 RefPtr<CSSPrimitiveValue> listStyle;
3214 if (!i) // Make the list style default decimal
3215 listStyle = CSSPrimitiveValue::create(CSSValueDecimal - CSSValueDisc, CSSPrimitiveValue::CSS_NUMBER);
3217 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
3221 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
3225 if (i->id == CSSValueNone)
3226 ls = CSSValueKatakanaIroha - CSSValueDisc + 1;
3227 else if (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha)
3228 ls = i->id - CSSValueDisc;
3232 listStyle = CSSPrimitiveValue::create(ls, (CSSPrimitiveValue::UnitTypes) i->unit);
3235 return CSSPrimitiveValue::create(Counter::create(identifier.release(), listStyle.release(), separator.release()));
3238 bool CSSParser::parseShape(int propId, bool important)
3240 CSSParserValue* value = m_valueList->current();
3241 CSSParserValueList* args = value->function->args;
3243 if (!equalIgnoringCase(value->function->name, "rect(") || !args)
3246 // rect(t, r, b, l) || rect(t r b l)
3247 if (args->size() != 4 && args->size() != 7)
3249 RefPtr<Rect> rect = Rect::create();
3252 CSSParserValue* a = args->current();
3254 valid = a->id == CSSValueAuto || validUnit(a, FLength, m_strict);
3257 RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
3258 CSSPrimitiveValue::createIdentifier(CSSValueAuto) :
3259 CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
3261 rect->setTop(length);
3263 rect->setRight(length);
3265 rect->setBottom(length);
3267 rect->setLeft(length);
3269 if (a && args->size() == 7) {
3270 if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
3280 addProperty(propId, CSSPrimitiveValue::create(rect.release()), important);
3281 m_valueList->next();
3287 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
3288 bool CSSParser::parseFont(bool important)
3291 CSSParserValue *value = m_valueList->current();
3292 RefPtr<FontValue> font = FontValue::create();
3293 // optional font-style, font-variant and font-weight
3297 if (id == CSSValueNormal) {
3298 // do nothing, it's the inital value for all three
3299 } else if (id == CSSValueItalic || id == CSSValueOblique) {
3302 font->style = CSSPrimitiveValue::createIdentifier(id);
3303 } else if (id == CSSValueSmallCaps) {
3306 font->variant = CSSPrimitiveValue::createIdentifier(id);
3307 } else if (id >= CSSValueBold && id <= CSSValueLighter) {
3310 font->weight = CSSPrimitiveValue::createIdentifier(id);
3314 } else if (!font->weight && validUnit(value, FInteger | FNonNeg, true)) {
3315 int weight = (int)value->fValue;
3319 else if (weight == 200)
3321 else if (weight == 300)
3323 else if (weight == 400)
3325 else if (weight == 500)
3327 else if (weight == 600)
3329 else if (weight == 700)
3331 else if (weight == 800)
3333 else if (weight == 900)
3337 font->weight = CSSPrimitiveValue::createIdentifier(val);
3345 value = m_valueList->next();
3350 // set undefined values to default
3352 font->style = CSSPrimitiveValue::createIdentifier(CSSValueNormal);
3354 font->variant = CSSPrimitiveValue::createIdentifier(CSSValueNormal);
3356 font->weight = CSSPrimitiveValue::createIdentifier(CSSValueNormal);
3358 // now a font size _must_ come
3359 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
3360 if (value->id >= CSSValueXxSmall && value->id <= CSSValueLarger)
3361 font->size = CSSPrimitiveValue::createIdentifier(value->id);
3362 else if (validUnit(value, FLength | FPercent | FNonNeg, m_strict))
3363 font->size = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
3364 value = m_valueList->next();
3365 if (!font->size || !value)
3368 if (value->unit == CSSParserValue::Operator && value->iValue == '/') {
3370 value = m_valueList->next();
3373 if (value->id == CSSValueNormal) {
3374 // default value, nothing to do
3375 } else if (validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict))
3376 font->lineHeight = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
3379 value = m_valueList->next();
3384 if (!font->lineHeight)
3385 font->lineHeight = CSSPrimitiveValue::createIdentifier(CSSValueNormal);
3387 // font family must come now
3388 font->family = parseFontFamily();
3390 if (m_valueList->current() || !font->family)
3393 addProperty(CSSPropertyFont, font.release(), important);
3397 PassRefPtr<CSSValueList> CSSParser::parseFontFamily()
3399 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
3400 CSSParserValue* value = m_valueList->current();
3402 FontFamilyValue* currFamily = 0;
3404 CSSParserValue* nextValue = m_valueList->next();
3405 bool nextValBreaksFont = !nextValue ||
3406 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
3407 bool nextValIsFontName = nextValue &&
3408 ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
3409 (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
3411 if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
3413 currFamily->appendSpaceSeparated(value->string.characters, value->string.length);
3414 else if (nextValBreaksFont || !nextValIsFontName)
3415 list->append(CSSPrimitiveValue::createIdentifier(value->id));
3417 RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string);
3418 currFamily = newFamily.get();
3419 list->append(newFamily.release());
3421 } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
3422 // Strings never share in a family name.
3424 list->append(FontFamilyValue::create(value->string));
3425 } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
3427 currFamily->appendSpaceSeparated(value->string.characters, value->string.length);
3428 else if (nextValBreaksFont || !nextValIsFontName)
3429 list->append(FontFamilyValue::create(value->string));
3431 RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string);
3432 currFamily = newFamily.get();
3433 list->append(newFamily.release());
3442 if (nextValBreaksFont) {
3443 value = m_valueList->next();
3446 else if (nextValIsFontName)
3451 if (!list->length())
3453 return list.release();
3456 bool CSSParser::parseFontStyle(bool important)
3458 RefPtr<CSSValueList> values;
3459 if (m_valueList->size() > 1)
3460 values = CSSValueList::createCommaSeparated();
3461 CSSParserValue* val;
3462 bool expectComma = false;
3463 while ((val = m_valueList->current())) {
3464 RefPtr<CSSPrimitiveValue> parsedValue;
3467 if (val->id == CSSValueNormal || val->id == CSSValueItalic || val->id == CSSValueOblique)
3468 parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
3469 else if (val->id == CSSValueAll && !values) {
3470 // 'all' is only allowed in @font-face and with no other values. Make a value list to
3471 // indicate that we are in the @font-face case.
3472 values = CSSValueList::createCommaSeparated();
3473 parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
3475 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3476 expectComma = false;
3477 m_valueList->next();
3484 m_valueList->next();
3487 values->append(parsedValue.release());
3489 addProperty(CSSPropertyFontStyle, parsedValue.release(), important);
3494 if (values && values->length()) {
3495 m_hasFontFaceOnlyValues = true;
3496 addProperty(CSSPropertyFontStyle, values.release(), important);
3503 bool CSSParser::parseFontVariant(bool important)
3505 RefPtr<CSSValueList> values;
3506 if (m_valueList->size() > 1)
3507 values = CSSValueList::createCommaSeparated();
3508 CSSParserValue* val;
3509 bool expectComma = false;
3510 while ((val = m_valueList->current())) {
3511 RefPtr<CSSPrimitiveValue> parsedValue;
3514 if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
3515 parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
3516 else if (val->id == CSSValueAll && !values) {
3517 // 'all' is only allowed in @font-face and with no other values. Make a value list to
3518 // indicate that we are in the @font-face case.
3519 values = CSSValueList::createCommaSeparated();
3520 parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
3522 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3523 expectComma = false;
3524 m_valueList->next();
3531 m_valueList->next();
3534 values->append(parsedValue.release());
3536 addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
3541 if (values && values->length()) {
3542 m_hasFontFaceOnlyValues = true;
3543 addProperty(CSSPropertyFontVariant, values.release(), important);
3550 bool CSSParser::parseFontWeight(bool important)
3552 RefPtr<CSSValueList> values;
3553 if (m_valueList->size() > 1)
3554 values = CSSValueList::createCommaSeparated();
3555 CSSParserValue* val;
3556 bool expectComma = false;
3557 while ((val = m_valueList->current())) {
3558 RefPtr<CSSPrimitiveValue> parsedValue;
3561 if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
3562 if (val->id >= CSSValueNormal && val->id <= CSSValue900)
3563 parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
3564 else if (val->id == CSSValueAll && !values) {
3565 // 'all' is only allowed in @font-face and with no other values. Make a value list to
3566 // indicate that we are in the @font-face case.
3567 values = CSSValueList::createCommaSeparated();
3568 parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
3570 } else if (validUnit(val, FInteger | FNonNeg, false)) {
3571 int weight = static_cast<int>(val->fValue);
3572 if (!(weight % 100) && weight >= 100 && weight <= 900)
3573 parsedValue = CSSPrimitiveValue::createIdentifier(CSSValue100 + weight / 100 - 1);
3575 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3576 expectComma = false;
3577 m_valueList->next();
3584 m_valueList->next();
3587 values->append(parsedValue.release());
3589 addProperty(CSSPropertyFontWeight, parsedValue.release(), important);
3594 if (values && values->length()) {
3595 m_hasFontFaceOnlyValues = true;
3596 addProperty(CSSPropertyFontWeight, values.release(), important);
3603 static bool isValidFormatFunction(CSSParserValue* val)
3605 CSSParserValueList* args = val->function->args;
3606 return equalIgnoringCase(val->function->name, "format(") && (args->current()->unit == CSSPrimitiveValue::CSS_STRING || args->current()->unit == CSSPrimitiveValue::CSS_IDENT);
3609 bool CSSParser::parseFontFaceSrc()
3611 RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
3612 CSSParserValue* val;
3613 bool expectComma = false;
3614 bool allowFormat = false;
3615 bool failed = false;
3616 RefPtr<CSSFontFaceSrcValue> uriValue;
3617 while ((val = m_valueList->current())) {
3618 RefPtr<CSSFontFaceSrcValue> parsedValue;
3619 if (val->unit == CSSPrimitiveValue::CSS_URI && !expectComma && m_styleSheet) {
3620 // FIXME: The completeURL call should be done when using the CSSFontFaceSrcValue,
3621 // not when creating it.
3622 parsedValue = CSSFontFaceSrcValue::create(m_styleSheet->completeURL(val->string));
3623 uriValue = parsedValue;
3626 } else if (val->unit == CSSParserValue::Function) {
3627 // There are two allowed functions: local() and format().
3628 CSSParserValueList* args = val->function->args;
3629 if (args && args->size() == 1) {
3630 if (equalIgnoringCase(val->function->name, "local(") && !expectComma) {
3632 allowFormat = false;
3633 CSSParserValue* a = args->current();
3635 parsedValue = CSSFontFaceSrcValue::createLocal(a->string);
3636 } else if (allowFormat && uriValue && isValidFormatFunction(val)) {
3638 allowFormat = false;
3639 uriValue->setFormat(args->current()->string);
3641 m_valueList->next();
3645 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',' && expectComma) {
3646 expectComma = false;
3647 allowFormat = false;
3649 m_valueList->next();
3654 values->append(parsedValue.release());
3659 m_valueList->next();
3662 if (values->length() && !failed) {
3663 addProperty(CSSPropertySrc, values.release(), m_important);
3664 m_valueList->next();
3671 bool CSSParser::parseFontFaceUnicodeRange()
3673 RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3674 bool failed = false;
3675 bool operatorExpected = false;
3676 for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
3677 if (operatorExpected) {
3678 if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
3683 if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
3688 String rangeString = m_valueList->current()->string;
3691 unsigned length = rangeString.length();
3699 while (i < length) {
3700 UChar c = rangeString[i];
3701 if (c == '-' || c == '?')
3704 if (c >= '0' && c <= '9')
3706 else if (c >= 'A' && c <= 'F')
3707 from += 10 + c - 'A';
3708 else if (c >= 'a' && c <= 'f')
3709 from += 10 + c - 'a';
3721 else if (rangeString[i] == '?') {
3723 while (i < length && rangeString[i] == '?') {
3730 to = from + span - 1;
3732 if (length < i + 2) {
3737 while (i < length) {
3738 UChar c = rangeString[i];
3740 if (c >= '0' && c <= '9')
3742 else if (c >= 'A' && c <= 'F')
3744 else if (c >= 'a' && c <= 'f')
3756 values->append(CSSUnicodeRangeValue::create(from, to));
3758 if (failed || !values->length())
3760 addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
3764 static inline bool isCSSWhitespace(UChar c)
3766 return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f';
3769 static inline bool parseColorInt(const UChar*& string, const UChar* end, UChar terminator, int& value)
3771 const UChar* current = string;
3773 bool negative = false;
3774 while (current != end && isCSSWhitespace(*current))
3776 if (current != end && *current == '-') {
3780 if (current == end || !isASCIIDigit(*current))
3782 while (current != end && isASCIIDigit(*current)) {
3783 int newValue = localValue * 10 + *current++ - '0';
3784 if (newValue >= 255) {
3785 // Clamp values at 255.
3787 while (current != end && isASCIIDigit(*current))
3791 localValue = newValue;
3793 while (current != end && isCSSWhitespace(*current))
3795 if (current == end || *current++ != terminator)
3797 // Clamp negative values at zero.
3798 value = negative ? 0 : localValue;
3803 bool CSSParser::parseColor(const String &name, RGBA32& rgb, bool strict)
3805 const UChar* characters = name.characters();
3806 unsigned length = name.length();
3808 if (!strict && length >= 3) {
3809 if (name[0] == '#') {
3810 if (Color::parseHexColor(characters + 1, length - 1, rgb))
3813 if (Color::parseHexColor(characters, length, rgb))
3818 // Try rgb() syntax.
3819 if (name.startsWith("rgb(")) {
3820 const UChar* current = characters + 4;
3821 const UChar* end = characters + length;
3825 if (!parseColorInt(current, end, ',', red))
3827 if (!parseColorInt(current, end, ',', green))
3829 if (!parseColorInt(current, end, ')', blue))
3833 rgb = makeRGB(red, green, blue);
3836 // Try named colors.
3838 tc.setNamedColor(name);
3846 static inline int colorIntFromValue(CSSParserValue* v)
3848 if (v->fValue <= 0.0)
3851 if (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE) {
3852 if (v->fValue >= 100.0)
3854 return static_cast<int>(v->fValue * 256.0 / 100.0);
3857 if (v->fValue >= 255.0)
3860 return static_cast<int>(v->fValue);
3863 bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
3865 CSSParserValueList* args = value->function->args;
3866 CSSParserValue* v = args->current();
3867 Units unitType = FUnknown;
3868 // Get the first value and its type
3869 if (validUnit(v, FInteger, true))
3870 unitType = FInteger;
3871 else if (validUnit(v, FPercent, true))
3872 unitType = FPercent;
3875 colorArray[0] = colorIntFromValue(v);
3876 for (int i = 1; i < 3; i++) {
3878 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
3881 if (!validUnit(v, unitType, true))
3883 colorArray[i] = colorIntFromValue(v);
3887 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
3890 if (!validUnit(v, FNumber, true))
3892 // Convert the floating pointer number of alpha to an integer in the range [0, 256),
3893 // with an equal distribution across all 256 values.
3894 colorArray[3] = static_cast<int>(max(0.0, min(1.0, v->fValue)) * nextafter(256.0, 0.0));
3899 // The CSS3 specification defines the format of a HSL color as
3900 // hsl(<number>, <percent>, <percent>)
3901 // and with alpha, the format is
3902 // hsla(<number>, <percent>, <percent>, <number>)
3903 // The first value, HUE, is in an angle with a value between 0 and 360
3904 bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
3906 CSSParserValueList* args = value->function->args;
3907 CSSParserValue* v = args->current();
3908 // Get the first value
3909 if (!validUnit(v, FNumber, true))
3911 // normalize the Hue value and change it to be between 0 and 1.0
3912 colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
3913 for (int i = 1; i < 3; i++) {
3915 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
3918 if (!validUnit(v, FPercent, true))
3920 colorArray[i] = max(0.0, min(100.0, v->fValue)) / 100.0; // needs to be value between 0 and 1.0
3924 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
3927 if (!validUnit(v, FNumber, true))
3929 colorArray[3] = max(0.0, min(1.0, v->fValue));
3934 PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value)
3936 RGBA32 c = Color::transparent;
3937 if (!parseColorFromValue(value ? value : m_valueList->current(), c))
3939 return CSSPrimitiveValue::createColor(c);
3942 bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
3944 if (!m_strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
3945 value->fValue >= 0. && value->fValue < 1000000.) {
3946 String str = String::format("%06d", (int)(value->fValue+.5));
3947 if (!CSSParser::parseColor(str, c, m_strict))
3949 } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
3950 value->unit == CSSPrimitiveValue::CSS_IDENT ||
3951 (!m_strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
3952 if (!CSSParser::parseColor(value->string, c, m_strict && value->unit == CSSPrimitiveValue::CSS_IDENT))
3954 } else if (value->unit == CSSParserValue::Function &&
3955 value->function->args != 0 &&
3956 value->function->args->size() == 5 /* rgb + two commas */ &&
3957 equalIgnoringCase(value->function->name, "rgb(")) {
3959 if (!parseColorParameters(value, colorValues, false))
3961 c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
3963 if (value->unit == CSSParserValue::Function &&
3964 value->function->args != 0 &&
3965 value->function->args->size() == 7 /* rgba + three commas */ &&
3966 equalIgnoringCase(value->function->name, "rgba(")) {
3968 if (!parseColorParameters(value, colorValues, true))
3970 c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
3971 } else if (value->unit == CSSParserValue::Function &&
3972 value->function->args != 0 &&
3973 value->function->args->size() == 5 /* hsl + two commas */ &&
3974 equalIgnoringCase(value->function->name, "hsl(")) {
3975 double colorValues[3];
3976 if (!parseHSLParameters(value, colorValues, false))
3978 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
3979 } else if (value->unit == CSSParserValue::Function &&
3980 value->function->args != 0 &&
3981 value->function->args->size() == 7 /* hsla + three commas */ &&
3982 equalIgnoringCase(value->function->name, "hsla(")) {
3983 double colorValues[4];
3984 if (!parseHSLParameters(value, colorValues, true))
3986 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
3994 // This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return)
3995 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
3996 struct ShadowParseContext {
3997 ShadowParseContext(CSSPropertyID prop)
4002 , allowSpread(false)
4004 , allowStyle(prop == CSSPropertyWebkitBoxShadow)
4009 bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
4013 // Handle the ,, case gracefully by doing nothing.
4014 if (x || y || blur || spread || color || style) {
4016 values = CSSValueList::createCommaSeparated();
4018 // Construct the current shadow value and add it to the list.
4019 values->append(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
4022 // Now reset for the next shadow value.
4035 allowSpread = false;
4036 allowStyle = property == CSSPropertyWebkitBoxShadow;
4039 void commitLength(CSSParserValue* v)
4041 RefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit);
4050 } else if (allowY) {
4055 allowStyle = property == CSSPropertyWebkitBoxShadow;
4057 } else if (allowBlur) {
4058 blur = val.release();
4060 allowSpread = property == CSSPropertyWebkitBoxShadow;
4061 } else if (allowSpread) {
4062 spread = val.release();
4063 allowSpread = false;
4067 void commitColor(PassRefPtr<CSSPrimitiveValue> val)
4076 allowSpread = false;
4077 allowStyle = property == CSSPropertyWebkitBoxShadow;
4081 void commitStyle(CSSParserValue* v)
4083 style = CSSPrimitiveValue::createIdentifier(v->id);
4089 allowSpread = false;
4094 CSSPropertyID property;
4096 RefPtr<CSSValueList> values;
4097 RefPtr<CSSPrimitiveValue> x;
4098 RefPtr<CSSPrimitiveValue> y;
4099 RefPtr<CSSPrimitiveValue> blur;
4100 RefPtr<CSSPrimitiveValue> spread;
4101 RefPtr<CSSPrimitiveValue> style;
4102 RefPtr<CSSPrimitiveValue> color;
4113 bool CSSParser::parseShadow(int propId, bool important)
4115 ShadowParseContext context(static_cast<CSSPropertyID>(propId));
4116 CSSParserValue* val;
4117 while ((val = m_valueList->current())) {
4118 // Check for a comma break first.
4119 if (val->unit == CSSParserValue::Operator) {
4120 if (val->iValue != ',' || !context.allowBreak)
4121 // Other operators aren't legal or we aren't done with the current shadow
4122 // value. Treat as invalid.
4125 // -webkit-svg-shadow does not support multiple values.
4126 if (static_cast<CSSPropertyID>(propId) == CSSPropertyWebkitSvgShadow)
4129 // The value is good. Commit it.
4130 context.commitValue();
4131 } else if (validUnit(val, FLength, true)) {
4132 // We required a length and didn't get one. Invalid.
4133 if (!context.allowLength())
4136 // A length is allowed here. Construct the value and add it.
4137 context.commitLength(val);
4138 } else if (val->id == CSSValueInset) {
4139 if (!context.allowStyle)
4142 context.commitStyle(val);
4144 // The only other type of value that's ok is a color value.
4145 RefPtr<CSSPrimitiveValue> parsedColor;
4146 bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu ||
4147 (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && !m_strict));
4149 if (!context.allowColor)
4151 parsedColor = CSSPrimitiveValue::createIdentifier(val->id);
4155 // It's not built-in. Try to parse it as a color.
4156 parsedColor = parseColor(val);
4158 if (!parsedColor || !context.allowColor)
4159 return false; // This value is not a color or length and is invalid or
4160 // it is a color, but a color isn't allowed at this point.
4162 context.commitColor(parsedColor.release());
4165 m_valueList->next();
4168 if (context.allowBreak) {
4169 context.commitValue();
4170 if (context.values->length()) {
4171 addProperty(propId, context.values.release(), important);
4172 m_valueList->next();
4180 bool CSSParser::parseReflect(int propId, bool important)
4182 // box-reflect: <direction> <offset> <mask>
4184 // Direction comes first.
4185 CSSParserValue* val = m_valueList->current();
4186 CSSReflectionDirection direction;
4189 direction = ReflectionAbove;
4192 direction = ReflectionBelow;
4195 direction = ReflectionLeft;
4198 direction = ReflectionRight;
4204 // The offset comes next.
4205 val = m_valueList->next();
4206 RefPtr<CSSPrimitiveValue> offset;
4208 offset = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_PX);
4210 if (!validUnit(val, FLength | FPercent, m_strict))
4212 offset = CSSPrimitiveValue::create(val->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(val->unit));
4215 // Now for the mask.
4216 RefPtr<CSSValue> mask;
4217 val = m_valueList->next();
4219 if (!parseBorderImage(propId, important, mask))
4223 RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction, offset.release(), mask.release());
4224 addProperty(propId, reflectValue.release(), important);
4225 m_valueList->next();
4229 struct BorderImageParseContext {
4230 BorderImageParseContext()
4231 : m_allowBreak(false)
4232 , m_allowNumber(false)
4233 , m_allowSlash(false)
4234 , m_allowWidth(false)
4235 , m_allowRule(false)
4240 , m_horizontalRule(0)
4244 bool allowBreak() const { return m_allowBreak; }
4245 bool allowNumber() const { return m_allowNumber; }
4246 bool allowSlash() const { return m_allowSlash; }
4247 bool allowWidth() const { return m_allowWidth; }
4248 bool allowRule() const { return m_allowRule; }
4250 void commitImage(PassRefPtr<CSSValue> image) { m_image = image; m_allowNumber = true; }
4251 void commitNumber(CSSParserValue* v)
4253 PassRefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit);
4265 m_allowBreak = m_allowSlash = m_allowRule = true;
4266 m_allowNumber = !m_left;
4268 void commitSlash() { m_allowBreak = m_allowSlash = m_allowNumber = false; m_allowWidth = true; }
4269 void commitWidth(CSSParserValue* val)
4273 else if (!m_borderRight)
4274 m_borderRight = val;
4275 else if (!m_borderBottom)
4276 m_borderBottom = val;
4278 ASSERT(!m_borderLeft);
4282 m_allowBreak = m_allowRule = true;
4283 m_allowWidth = !m_borderLeft;
4285 void commitRule(int keyword)
4287 if (!m_horizontalRule)
4288 m_horizontalRule = keyword;
4289 else if (!m_verticalRule)
4290 m_verticalRule = keyword;
4291 m_allowRule = !m_verticalRule;
4293 PassRefPtr<CSSValue> commitBorderImage(CSSParser* p, bool important)
4295 // We need to clone and repeat values for any omissions.
4297 m_right = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
4298 m_bottom = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
4299 m_left = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
4302 m_bottom = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
4303 m_left = CSSPrimitiveValue::create(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType());
4306 m_left = CSSPrimitiveValue::create(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType());
4308 // Now build a rect value to hold all four of our primitive values.
4309 RefPtr<Rect> rect = Rect::create();
4310 rect->setTop(m_top);
4311 rect->setRight(m_right);
4312 rect->setBottom(m_bottom);
4313 rect->setLeft(m_left);
4315 // Fill in STRETCH as the default if it wasn't specified.
4316 if (!m_horizontalRule)
4317 m_horizontalRule = CSSValueStretch;
4319 // The vertical rule should match the horizontal rule if unspecified.
4320 if (!m_verticalRule)
4321 m_verticalRule = m_horizontalRule;
4323 // 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
4324 // list and then make our parsing machinery do the parsing.
4326 CSSParserValueList newList;
4327 newList.addValue(*m_borderTop);
4329 newList.addValue(*m_borderRight);
4331 newList.addValue(*m_borderBottom);
4333 newList.addValue(*m_borderLeft);
4334 CSSParserValueList* oldList = p->m_valueList;
4335 p->m_valueList = &newList;
4336 p->parseValue(CSSPropertyBorderWidth, important);
4337 p->m_valueList = oldList;
4340 // Make our new border image value now.
4341 return CSSBorderImageValue::create(m_image, rect.release(), m_horizontalRule, m_verticalRule);
4350 RefPtr<CSSValue> m_image;
4352 RefPtr<CSSPrimitiveValue> m_top;
4353 RefPtr<CSSPrimitiveValue> m_right;
4354 RefPtr<CSSPrimitiveValue> m_bottom;
4355 RefPtr<CSSPrimitiveValue> m_left;
4357 CSSParserValue* m_borderTop;
4358 CSSParserValue* m_borderRight;
4359 CSSParserValue* m_borderBottom;
4360 CSSParserValue* m_borderLeft;
4362 int m_horizontalRule;
4366 bool CSSParser::parseBorderImage(int propId, bool important, RefPtr<CSSValue>& result)
4368 // Look for an image initially. If the first value is not a URI, then we're done.
4369 BorderImageParseContext context;
4370 CSSParserValue* val = m_valueList->current();
4371 if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
4372 // FIXME: The completeURL call should be done when using the CSSImageValue,
4373 // not when creating it.
4374 context.commitImage(CSSImageValue::create(m_styleSheet->completeURL(val->string)));
4375 } else if (val->unit == CSSParserValue::Function) {
4376 RefPtr<CSSValue> value;
4377 if ((equalIgnoringCase(val->function->name, "-webkit-gradient(") && parseGradient(value)) ||
4378 (equalIgnoringCase(val->function->name, "-webkit-canvas(") && parseCanvas(value)))
4379 context.commitImage(value);
4385 while ((val = m_valueList->next())) {
4386 if (context.allowNumber() && validUnit(val, FInteger | FNonNeg | FPercent, true)) {
4387 context.commitNumber(val);
4388 } else if (propId == CSSPropertyWebkitBorderImage && context.allowSlash() && val->unit == CSSParserValue::Operator && val->iValue == '/') {
4389 context.commitSlash();
4390 } else if (context.allowWidth() &&
4391 (val->id == CSSValueThin || val->id == CSSValueMedium || val->id == CSSValueThick || validUnit(val, FLength, m_strict))) {
4392 context.commitWidth(val);
4393 } else if (context.allowRule() &&
4394 (val->id == CSSValueStretch || val->id == CSSValueRound || val->id == CSSValueRepeat)) {
4395 context.commitRule(val->id);
4397 // Something invalid was encountered.
4402 if (context.allowNumber() && propId != CSSPropertyWebkitBorderImage) {
4403 // Allow the slices to be omitted for images that don't fit to a border. We just set the slices to be 0.
4404 context.m_top = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_NUMBER);
4405 context.m_allowBreak = true;
4408 if (context.allowBreak()) {
4409 // Need to fully commit as a single value.
4410 result = context.commitBorderImage(this, important);
4417 static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4])
4423 radii[1] = radii[0];
4424 radii[2] = radii[0];
4426 radii[3] = radii[1];
4429 bool CSSParser::parseBorderRadius(int propId, bool important)
4431 unsigned num = m_valueList->size();
4435 RefPtr<CSSPrimitiveValue> radii[2][4];
4437 unsigned indexAfterSlash = 0;
4438 for (unsigned i = 0; i < num; ++i) {
4439 CSSParserValue* value = m_valueList->valueAt(i);
4440 if (value->unit == CSSParserValue::Operator) {
4441 if (value->iValue != '/')
4444 if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
4447 indexAfterSlash = i + 1;
4448 completeBorderRadii(radii[0]);
4452 if (i - indexAfterSlash >= 4)
4455 if (!validUnit(value, FLength, m_strict))
4458 RefPtr<CSSPrimitiveValue> radius = CSSPrimitiveValue::create(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
4460 if (!indexAfterSlash) {
4461 radii[0][i] = radius;
4463 // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
4464 if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
4465 indexAfterSlash = 1;
4466 completeBorderRadii(radii[0]);
4469 radii[1][i - indexAfterSlash] = radius.release();
4472 if (!indexAfterSlash) {
4473 completeBorderRadii(radii[0]);
4474 for (unsigned i = 0; i < 4; ++i)
4475 radii[1][i] = radii[0][i];
4477 completeBorderRadii(radii[1]);
4479 addProperty(CSSPropertyBorderTopLeftRadius, CSSPrimitiveValue::create(Pair::create(radii[0][0].release(), radii[1][0].release())), important);
4480 addProperty(CSSPropertyBorderTopRightRadius, CSSPrimitiveValue::create(Pair::create(radii[0][1].release(), radii[1][1].release())), important);
4481 addProperty(CSSPropertyBorderBottomRightRadius, CSSPrimitiveValue::create(Pair::create(radii[0][2].release(), radii[1][2].release())), important);
4482 addProperty(CSSPropertyBorderBottomLeftRadius, CSSPrimitiveValue::create(Pair::create(radii[0][3].release(), radii[1][3].release())), important);
4486 bool CSSParser::parseCounter(int propId, int defaultValue, bool important)
4488 enum { ID, VAL } state = ID;
4490 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
4491 RefPtr<CSSPrimitiveValue> counterName;
4494 CSSParserValue* val = m_valueList->current();
4497 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
4498 counterName = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
4500 m_valueList->next();
4505 int i = defaultValue;
4506 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
4507 i = (int)val->fValue;
4508 m_valueList->next();
4511 list->append(CSSPrimitiveValue::create(Pair::create(counterName.release(),
4512 CSSPrimitiveValue::create(i, CSSPrimitiveValue::CSS_NUMBER))));
4520 if (list->length() > 0) {
4521 addProperty(propId, list.release(), important);
4528 static PassRefPtr<CSSPrimitiveValue> parseGradientPoint(CSSParserValue* a, bool horizontal)
4530 RefPtr<CSSPrimitiveValue> result;
4531 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
4532 if ((equalIgnoringCase(a->string, "left") && horizontal)
4533 || (equalIgnoringCase(a->string, "top") && !horizontal))
4534 result = CSSPrimitiveValue::create(0., CSSPrimitiveValue::CSS_PERCENTAGE);
4535 else if ((equalIgnoringCase(a->string, "right") && horizontal)
4536 || (equalIgnoringCase(a->string, "bottom") && !horizontal))
4537 result = CSSPrimitiveValue::create(100., CSSPrimitiveValue::CSS_PERCENTAGE);
4538 else if (equalIgnoringCase(a->string, "center"))
4539 result = CSSPrimitiveValue::create(50., CSSPrimitiveValue::CSS_PERCENTAGE);
4540 } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
4541 result = CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit);
4545 static bool parseGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
4547 if (a->unit != CSSParserValue::Function)
4550 if (!equalIgnoringCase(a->function->name, "from(") &&
4551 !equalIgnoringCase(a->function->name, "to(") &&
4552 !equalIgnoringCase(a->function->name, "color-stop("))
4555 CSSParserValueList* args = a->function->args;
4559 if (equalIgnoringCase(a->function->name, "from(")
4560 || equalIgnoringCase(a->function->name, "to(")) {
4561 // The "from" and "to" stops expect 1 argument.
4562 if (args->size() != 1)
4565 if (equalIgnoringCase(a->function->name, "from("))
4570 int id = args->current()->id;
4571 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
4572 stop.m_color = CSSPrimitiveValue::createIdentifier(id);
4574 stop.m_color = p->parseColor(args->current());
4579 // The "color-stop" function expects 3 arguments.
4580 if (equalIgnoringCase(a->function->name, "color-stop(")) {
4581 if (args->size() != 3)
4584 CSSParserValue* stopArg = args->current();
4585 if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
4586 stop.m_stop = (float)stopArg->fValue / 100.f;
4587 else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
4588 stop.m_stop = (float)stopArg->fValue;
4592 stopArg = args->next();
4593 if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
4596 stopArg = args->next();
4597 int id = stopArg->id;
4598 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
4599 stop.m_color = CSSPrimitiveValue::createIdentifier(id);
4601 stop.m_color = p->parseColor(stopArg);
4609 bool CSSParser::parseGradient(RefPtr<CSSValue>& gradient)
4611 RefPtr<CSSGradientValue> result = CSSGradientValue::create();
4613 // Walk the arguments.
4614 CSSParserValueList* args = m_valueList->current()->function->args;
4615 if (!args || args->size() == 0)
4618 // The first argument is the gradient type. It is an identifier.
4619 CSSParserValue* a = args->current();
4620 if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
4622 if (equalIgnoringCase(a->string, "linear"))
4623 result->setType(CSSLinearGradient);
4624 else if (equalIgnoringCase(a->string, "radial"))
4625 result->setType(CSSRadialGradient);
4631 if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
4634 // Next comes the starting point for the gradient as an x y pair. There is no
4635 // comma between the x and the y values.
4636 // First X. It can be left, right, number or percent.
4640 RefPtr<CSSPrimitiveValue> point = parseGradientPoint(a, true);
4643 result->setFirstX(point.release());
4645 // First Y. It can be top, bottom, number or percent.
4649 point = parseGradientPoint(a, false);
4652 result->setFirstY(point.release());
4654 // Comma after the first point.
4656 if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
4659 // For radial gradients only, we now expect a numeric radius.
4660 if (result->type() == CSSRadialGradient) {
4662 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
4664 result->setFirstRadius(CSSPrimitiveValue::create(a->fValue, CSSPrimitiveValue::CSS_NUMBER));
4666 // Comma after the first radius.
4668 if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
4672 // Next is the ending point for the gradient as an x, y pair.
4673 // Second X. It can be left, right, number or percent.
4677 point = parseGradientPoint(a, true);
4680 result->setSecondX(point.release());
4682 // Second Y. It can be top, bottom, number or percent.
4686 point = parseGradientPoint(a, false);
4689 result->setSecondY(point.release());
4691 // For radial gradients only, we now expect the second radius.
4692 if (result->type() == CSSRadialGradient) {
4693 // Comma after the second point.
4695 if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
4699 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
4701 result->setSecondRadius(CSSPrimitiveValue::create(a->fValue, CSSPrimitiveValue::CSS_NUMBER));
4704 // We now will accept any number of stops (0 or more).
4707 // Look for the comma before the next stop.
4708 if (a->unit != CSSParserValue::Operator || a->iValue != ',')
4711 // Now examine the stop itself.
4716 // The function name needs to be one of "from", "to", or "color-stop."
4717 CSSGradientColorStop stop;
4718 if (!parseGradientColorStop(this, a, stop))
4720 result->addStop(stop);
4726 gradient = result.release();
4730 bool CSSParser::parseCanvas(RefPtr<CSSValue>& canvas)
4732 RefPtr<CSSCanvasValue> result = CSSCanvasValue::create();
4734 // Walk the arguments.
4735 CSSParserValueList* args = m_valueList->current()->function->args;
4736 if (!args || args->size() != 1)
4739 // The first argument is the canvas name. It is an identifier.
4740 CSSParserValue* a = args->current();
4741 if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
4743 result->setName(a->string);
4748 class TransformOperationInfo {
4750 TransformOperationInfo(const CSSParserString& name)
4751 : m_type(WebKitCSSTransformValue::UnknownTransformOperation)
4753 , m_allowSingleArgument(false)
4754 , m_unit(CSSParser::FUnknown)
4756 if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "scalex(") || equalIgnoringCase(name, "scaley(") || equalIgnoringCase(name, "scalez(")) {
4757 m_unit = CSSParser::FNumber;
4758 if (equalIgnoringCase(name, "scale("))
4759 m_type = WebKitCSSTransformValue::ScaleTransformOperation;
4760 else if (equalIgnoringCase(name, "scalex("))
4761 m_type = WebKitCSSTransformValue::ScaleXTransformOperation;
4762 else if (equalIgnoringCase(name, "scaley("))
4763 m_type = WebKitCSSTransformValue::ScaleYTransformOperation;
4765 m_type = WebKitCSSTransformValue::ScaleZTransformOperation;
4766 } else if (equalIgnoringCase(name, "scale3d(")) {
4767 m_type = WebKitCSSTransformValue::Scale3DTransformOperation;
4769 m_unit = CSSParser::FNumber;
4770 } else if (equalIgnoringCase(name, "rotate(")) {
4771 m_type = WebKitCSSTransformValue::RotateTransformOperation;
4772 m_unit = CSSParser::FAngle;
4773 } else if (equalIgnoringCase(name, "rotatex(") ||
4774 equalIgnoringCase(name, "rotatey(") ||
4775 equalIgnoringCase(name, "rotatez(")) {
4776 m_unit = CSSParser::FAngle;
4777 if (equalIgnoringCase(name, "rotatex("))
4778 m_type = WebKitCSSTransformValue::RotateXTransformOperation;
4779 else if (equalIgnoringCase(name, "rotatey("))
4780 m_type = WebKitCSSTransformValue::RotateYTransformOperation;
4782 m_type = WebKitCSSTransformValue::RotateZTransformOperation;
4783 } else if (equalIgnoringCase(name, "rotate3d(")) {
4784 m_type = WebKitCSSTransformValue::Rotate3DTransformOperation;
4786 m_unit = CSSParser::FNumber;
4787 } else if (equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "skewx(") || equalIgnoringCase(name, "skewy(")) {
4788 m_unit = CSSParser::FAngle;
4789 if (equalIgnoringCase(name, "skew("))
4790 m_type = WebKitCSSTransformValue::SkewTransformOperation;
4791 else if (equalIgnoringCase(name, "skewx("))
4792 m_type = WebKitCSSTransformValue::SkewXTransformOperation;
4794 m_type = WebKitCSSTransformValue::SkewYTransformOperation;
4795 } else if (equalIgnoringCase(name, "translate(") || equalIgnoringCase(name, "translatex(") || equalIgnoringCase(name, "translatey(") || equalIgnoringCase(name, "translatez(")) {
4796 m_unit = CSSParser::FLength | CSSParser::FPercent;
4797 if (equalIgnoringCase(name, "translate("))
4798 m_type = WebKitCSSTransformValue::TranslateTransformOperation;
4799 else if (equalIgnoringCase(name, "translatex("))
4800 m_type = WebKitCSSTransformValue::TranslateXTransformOperation;
4801 else if (equalIgnoringCase(name, "translatey("))
4802 m_type = WebKitCSSTransformValue::TranslateYTransformOperation;
4804 m_type = WebKitCSSTransformValue::TranslateZTransformOperation;
4805 } else if (equalIgnoringCase(name, "translate3d(")) {
4806 m_type = WebKitCSSTransformValue::Translate3DTransformOperation;
4808 m_unit = CSSParser::FLength | CSSParser::FPercent;
4809 } else if (equalIgnoringCase(name, "matrix(")) {
4810 m_type = WebKitCSSTransformValue::MatrixTransformOperation;
4812 m_unit = CSSParser::FNumber;
4813 } else if (equalIgnoringCase(name, "matrix3d(")) {
4814 m_type = WebKitCSSTransformValue::Matrix3DTransformOperation;
4816 m_unit = CSSParser::FNumber;
4817 } else if (equalIgnoringCase(name, "perspective(")) {
4818 m_type = WebKitCSSTransformValue::PerspectiveTransformOperation;
4819 m_unit = CSSParser::FNumber;
4822 if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "translate(")) {
4823 m_allowSingleArgument = true;
4828 WebKitCSSTransformValue::TransformOperationType type() const { return m_type; }
4829 unsigned argCount() const { return m_argCount; }
4830 CSSParser::Units unit() const { return m_unit; }
4832 bool unknown() const { return m_type == WebKitCSSTransformValue::UnknownTransformOperation; }
4833 bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
4836 WebKitCSSTransformValue::TransformOperationType m_type;
4837 unsigned m_argCount;
4838 bool m_allowSingleArgument;
4839 CSSParser::Units m_unit;
4842 PassRefPtr<CSSValueList> CSSParser::parseTransform()
4847 // The transform is a list of functional primitives that specify transform operations.
4848 // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation.
4849 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
4850 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
4851 if (value->unit != CSSParserValue::Function || !value->function)
4854 // Every primitive requires at least one argument.
4855 CSSParserValueList* args = value->function->args;
4859 // See if the specified primitive is one we understand.
4860 TransformOperationInfo info(value->function->name);
4864 if (!info.hasCorrectArgCount(args->size()))
4867 // Create the new WebKitCSSTransformValue for this operation and add it to our list.
4868 RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(info.type());
4869 list->append(transformValue);
4872 CSSParserValue* a = args->current();
4873 unsigned argNumber = 0;
4875 CSSParser::Units unit = info.unit();
4877 // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
4878 if (info.type() == WebKitCSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
4879 if (!validUnit(a, FAngle, true))
4881 } else if (!validUnit(a, unit, true))
4884 // Add the value to the current transform operation.
4885 transformValue->append(CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit));
4890 if (a->unit != CSSParserValue::Operator || a->iValue != ',')
4898 return list.release();
4901 bool CSSParser::parseTransformOrigin(int propId, int& propId1, int& propId2, int& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
4906 if (propId == CSSPropertyWebkitTransformOrigin) {
4907 propId1 = CSSPropertyWebkitTransformOriginX;
4908 propId2 = CSSPropertyWebkitTransformOriginY;
4909 propId3 = CSSPropertyWebkitTransformOriginZ;
4913 case CSSPropertyWebkitTransformOrigin:
4914 parseTransformOriginShorthand(value, value2, value3);
4915 // parseTransformOriginShorthand advances the m_valueList pointer
4917 case CSSPropertyWebkitTransformOriginX: {
4918 bool xFound = false, yFound = true;
4919 value = parseFillPositionXY(xFound, yFound);
4921 m_valueList->next();
4924 case CSSPropertyWebkitTransformOriginY: {
4925 bool xFound = true, yFound = false;
4926 value = parseFillPositionXY(xFound, yFound);
4928 m_valueList->next();
4931 case CSSPropertyWebkitTransformOriginZ: {
4932 if (validUnit(m_valueList->current(), FLength, m_strict))
4933 value = CSSPrimitiveValue::create(m_valueList->current()->fValue, (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit);
4935 m_valueList->next();
4943 bool CSSParser::parsePerspectiveOrigin(int propId, int& propId1, int& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2)
4947 if (propId == CSSPropertyWebkitPerspectiveOrigin) {
4948 propId1 = CSSPropertyWebkitPerspectiveOriginX;
4949 propId2 = CSSPropertyWebkitPerspectiveOriginY;
4953 case CSSPropertyWebkitPerspectiveOrigin:
4954 parseFillPosition(value, value2);
4956 case CSSPropertyWebkitPerspectiveOriginX: {
4957 bool xFound = false, yFound = true;
4958 value = parseFillPositionXY(xFound, yFound);
4960 m_valueList->next();
4963 case CSSPropertyWebkitPerspectiveOriginY: {
4964 bool xFound = true, yFound = false;
4965 value = parseFillPositionXY(xFound, yFound);
4967 m_valueList->next();
4975 static inline int yyerror(const char*) { return 1; }
4979 #include "CSSGrammar.h"
4981 int CSSParser::lex(void* yylvalWithoutType)
4983 YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType);
4988 UChar* t = text(&length);
5008 yylval->string.characters = t;
5009 yylval->string.length = length;
5018 case WEBKIT_KEYFRAMES_SYM:
5049 yylval->number = charactersToDouble(t, length);
5059 void CSSParser::recheckAtKeyword(const UChar* str, int len)
5061 String ruleName(str, len);
5062 if (equalIgnoringCase(ruleName, "@import"))
5064 else if (equalIgnoringCase(ruleName, "@page"))
5066 else if (equalIgnoringCase(ruleName, "@media"))
5068 else if (equalIgnoringCase(ruleName, "@font-face"))
5069 yyTok = FONT_FACE_SYM;
5070 else if (equalIgnoringCase(ruleName, "@charset"))
5071 yyTok = CHARSET_SYM;
5072 else if (equalIgnoringCase(ruleName, "@namespace"))
5073 yyTok = NAMESPACE_SYM;
5074 else if (equalIgnoringCase(ruleName, "@-webkit-keyframes"))
5075 yyTok = WEBKIT_KEYFRAMES_SYM;
5076 else if (equalIgnoringCase(ruleName, "@-webkit-mediaquery"))
5077 yyTok = WEBKIT_MEDIAQUERY_SYM;
5078 // FIXME: Add CSS Variables if we ever decide to turn it back on.
5081 UChar* CSSParser::text(int *length)
5083 UChar* start = yytext;
5095 // "url("{w}{string}{w}")"
5096 // "url("{w}{url}{w}")"
5097 // strip "url(" and ")"
5101 while (l && isCSSWhitespace(*start)) {
5105 while (l && isCSSWhitespace(start[l - 1]))
5107 if (l && (*start == '"' || *start == '\'')) {
5108 ASSERT(l >= 2 && start[l - 1] == *start);
5114 // "-webkit-var("{w}{ident}{w}")"
5115 // strip "-webkit-var(" and ")"
5119 while (l && isCSSWhitespace(*start)) {
5123 while (l && isCSSWhitespace(start[l - 1]))
5134 bool sawEscape = false;
5136 for (int i = 0; i < l; i++) {
5137 UChar* current = start + i;
5138 if (escape == current - 1) {
5139 if (isASCIIHexDigit(*current))
5141 if (yyTok == STRING &&
5142 (*current == '\n' || *current == '\r' || *current == '\f')) {
5143 // ### handle \r\n case
5144 if (*current != '\r')
5148 // in all other cases copy the char to output
5154 if (escape == current - 2 && yyTok == STRING &&
5155 *(current-1) == '\r' && *current == '\n') {
5159 if (escape > current - 7 && isASCIIHexDigit(*current))
5165 while (escape < current) {
5167 uc += toASCIIHexValue(*escape);
5170 // can't handle chars outside ucs2
5175 if (isCSSWhitespace(*current))
5178 if (!escape && *current == '\\') {
5189 while (escape < start+l) {
5191 uc += toASCIIHexValue(*escape);
5194 // can't handle chars outside ucs2
5200 *length = out - start;
5202 // If we have an unrecognized @-keyword, and if we handled any escapes at all, then
5203 // we should attempt to adjust yyTok to the correct type.
5204 if (yyTok == ATKEYWORD && sawEscape)
5205 recheckAtKeyword(start, *length);
5210 void CSSParser::countLines()
5212 for (UChar* current = yytext; current < yytext + yyleng; ++current) {
5213 if (*current == '\n')
5218 CSSSelector* CSSParser::createFloatingSelector()
5220 CSSSelector* selector = fastNew<CSSSelector>();
5221 m_floatingSelectors.add(selector);
5225 CSSSelector* CSSParser::sinkFloatingSelector(CSSSelector* selector)
5228 ASSERT(m_floatingSelectors.contains(selector));
5229 m_floatingSelectors.remove(selector);
5234 CSSParserValueList* CSSParser::createFloatingValueList()
5236 CSSParserValueList* list = new CSSParserValueList;
5237 m_floatingValueLists.add(list);
5241 CSSParserValueList* CSSParser::sinkFloatingValueList(CSSParserValueList* list)
5244 ASSERT(m_floatingValueLists.contains(list));
5245 m_floatingValueLists.remove(list);
5250 CSSParserFunction* CSSParser::createFloatingFunction()
5252 CSSParserFunction* function = new CSSParserFunction;
5253 m_floatingFunctions.add(function);
5257 CSSParserFunction* CSSParser::sinkFloatingFunction(CSSParserFunction* function)
5260 ASSERT(m_floatingFunctions.contains(function));
5261 m_floatingFunctions.remove(function);
5266 CSSParserValue& CSSParser::sinkFloatingValue(CSSParserValue& value)
5268 if (value.unit == CSSParserValue::Function) {
5269 ASSERT(m_floatingFunctions.contains(value.function));
5270 m_floatingFunctions.remove(value.function);
5275 MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
5277 delete m_floatingMediaQueryExp;
5278 m_floatingMediaQueryExp = new MediaQueryExp(mediaFeature, values);
5279 return m_floatingMediaQueryExp;
5282 MediaQueryExp* CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* e)
5284 ASSERT(e == m_floatingMediaQueryExp);
5285 m_floatingMediaQueryExp = 0;
5289 Vector<MediaQueryExp*>* CSSParser::createFloatingMediaQueryExpList()
5291 if (m_floatingMediaQueryExpList) {
5292 deleteAllValues(*m_floatingMediaQueryExpList);
5293 delete m_floatingMediaQueryExpList;
5295 m_floatingMediaQueryExpList = new Vector<MediaQueryExp*>;
5296 return m_floatingMediaQueryExpList;
5299 Vector<MediaQueryExp*>* CSSParser::sinkFloatingMediaQueryExpList(Vector<MediaQueryExp*>* l)
5301 ASSERT(l == m_floatingMediaQueryExpList);
5302 m_floatingMediaQueryExpList = 0;
5306 MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor r, const String& mediaType, Vector<MediaQueryExp*>* exprs)
5308 delete m_floatingMediaQuery;
5309 m_floatingMediaQuery = new MediaQuery(r, mediaType, exprs);
5310 return m_floatingMediaQuery;
5313 MediaQuery* CSSParser::createFloatingMediaQuery(Vector<MediaQueryExp*>* exprs)
5315 return createFloatingMediaQuery(MediaQuery::None, "all", exprs);
5318 MediaQuery* CSSParser::sinkFloatingMediaQuery(MediaQuery* mq)
5320 ASSERT(mq == m_floatingMediaQuery);
5321 m_floatingMediaQuery = 0;
5325 MediaList* CSSParser::createMediaList()
5327 RefPtr<MediaList> list = MediaList::create();
5328 MediaList* result = list.get();
5329 m_parsedStyleObjects.append(list.release());
5333 CSSRule* CSSParser::createCharsetRule(const CSSParserString& charset)
5337 RefPtr<CSSCharsetRule> rule = CSSCharsetRule::create(m_styleSheet, charset);
5338 CSSCharsetRule* result = rule.get();
5339 m_parsedStyleObjects.append(rule.release());
5343 CSSRule* CSSParser::createImportRule(const CSSParserString& url, MediaList* media)
5345 if (!media || !m_styleSheet || !m_allowImportRules)
5347 RefPtr<CSSImportRule> rule = CSSImportRule::create(m_styleSheet, url, media);
5348 CSSImportRule* result = rule.get();
5349 m_parsedStyleObjects.append(rule.release());
5353 CSSRule* CSSParser::createMediaRule(MediaList* media, CSSRuleList* rules)
5355 if (!media || !rules || !m_styleSheet)
5357 m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false;
5358 RefPtr<CSSMediaRule> rule = CSSMediaRule::create(m_styleSheet, media, rules);
5359 CSSMediaRule* result = rule.get();
5360 m_parsedStyleObjects.append(rule.release());
5364 CSSRuleList* CSSParser::createRuleList()
5366 RefPtr<CSSRuleList> list = CSSRuleList::create();
5367 CSSRuleList* listPtr = list.get();
5369 m_parsedRuleLists.append(list.release());
5373 WebKitCSSKeyframesRule* CSSParser::createKeyframesRule()
5375 m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false;
5376 RefPtr<WebKitCSSKeyframesRule> rule = WebKitCSSKeyframesRule::create(m_styleSheet);
5377 WebKitCSSKeyframesRule* rulePtr = rule.get();
5378 m_parsedStyleObjects.append(rule.release());
5382 CSSRule* CSSParser::createStyleRule(Vector<CSSSelector*>* selectors)
5384 m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false;
5385 CSSStyleRule* result = 0;
5388 RefPtr<CSSStyleRule> rule = CSSStyleRule::create(m_styleSheet, m_lastSelectorLineNumber);
5389 rule->adoptSelectorVector(*selectors);
5390 if (m_hasFontFaceOnlyValues)
5391 deleteFontFaceOnlyValues();
5392 rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties));
5393 result = rule.get();
5394 m_parsedStyleObjects.append(rule.release());
5396 m_ruleRanges->set(result, std::pair<unsigned, unsigned>(m_ruleBodyStartOffset, m_ruleBodyEndOffset));
5398 resetRuleBodyMarks();
5403 CSSRule* CSSParser::createFontFaceRule()
5405 m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false;
5406 RefPtr<CSSFontFaceRule> rule = CSSFontFaceRule::create(m_styleSheet);
5407 for (unsigned i = 0; i < m_numParsedProperties; ++i) {
5408 CSSProperty* property = m_parsedProperties[i];
5409 int id = property->id();
5410 if ((id == CSSPropertyFontWeight || id == CSSPropertyFontStyle || id == CSSPropertyFontVariant) && property->value()->isPrimitiveValue()) {
5411 RefPtr<CSSValue> value = property->m_value.release();
5412 property->m_value = CSSValueList::createCommaSeparated();
5413 static_cast<CSSValueList*>(property->m_value.get())->append(value.release());
5416 rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties));
5418 CSSFontFaceRule* result = rule.get();
5419 m_parsedStyleObjects.append(rule.release());
5423 void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
5425 if (!m_styleSheet || !m_allowNamespaceDeclarations)
5427 m_allowImportRules = false;
5428 m_allowVariablesRules = false;
5429 m_styleSheet->addNamespace(this, prefix, uri);
5432 #if !ENABLE(CSS_VARIABLES)
5434 CSSRule* CSSParser::createVariablesRule(MediaList*, bool)
5439 bool CSSParser::addVariable(const CSSParserString&, CSSParserValueList*)
5444 bool CSSParser::addVariableDeclarationBlock(const CSSParserString&)
5451 CSSRule* CSSParser::createVariablesRule(MediaList* mediaList, bool variablesKeyword)
5453 if (!m_allowVariablesRules)
5455 m_allowImportRules = false;
5456 RefPtr<CSSVariablesRule> rule = CSSVariablesRule::create(m_styleSheet, mediaList, variablesKeyword);
5457 rule->setDeclaration(CSSVariablesDeclaration::create(rule.get(), m_variableNames, m_variableValues));
5459 CSSRule* result = rule.get();
5460 m_parsedStyleObjects.append(rule.release());
5464 bool CSSParser::addVariable(const CSSParserString& name, CSSParserValueList* valueList)
5466 if (checkForVariables(valueList)) {
5470 m_variableNames.append(String(name));
5471 m_variableValues.append(CSSValueList::createFromParserValueList(valueList));
5475 bool CSSParser::addVariableDeclarationBlock(const CSSParserString&)
5477 // FIXME: Disabling declarations as variable values for now since they no longer have a common base class with CSSValues.
5479 m_variableNames.append(String(name));
5480 m_variableValues.append(CSSMutableStyleDeclaration::create(0, m_parsedProperties, m_numParsedProperties));
5488 CSSRule* CSSParser::createPageRule(CSSSelector* pageSelector)
5490 // FIXME: Margin at-rules are ignored.
5491 m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false;
5492 CSSPageRule* pageRule = 0;
5494 RefPtr<CSSPageRule> rule = CSSPageRule::create(m_styleSheet, pageSelector, m_lastSelectorLineNumber);
5495 rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties));
5496 pageRule = rule.get();
5497 m_parsedStyleObjects.append(rule.release());
5503 CSSRule* CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
5505 // FIXME: Implement margin at-rule here, using:
5506 // - marginBox: margin box
5507 // - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_numParsedProperties) are for this at-rule.
5508 // Don't forget to also update the action for page symbol in CSSGrammar.y such that margin at-rule data is cleared if page_selector is invalid.
5510 endDeclarationsForMarginBox();
5511 return 0; // until this method is implemented.
5514 void CSSParser::startDeclarationsForMarginBox()
5516 m_numParsedPropertiesBeforeMarginBox = m_numParsedProperties;
5519 void CSSParser::endDeclarationsForMarginBox()
5521 ASSERT(m_numParsedPropertiesBeforeMarginBox != INVALID_NUM_PARSED_PROPERTIES);
5522 rollbackLastProperties(m_numParsedProperties - m_numParsedPropertiesBeforeMarginBox);
5523 m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
5526 void CSSParser::clearVariables()
5528 m_variableNames.clear();
5529 m_variableValues.clear();
5532 bool CSSParser::parseVariable(CSSVariablesDeclaration* declaration, const String& variableName, const String& variableValue)
5534 #ifdef ANDROID_INSTRUMENT
5535 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
5537 m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
5539 String nameValuePair = variableName + ": ";
5540 nameValuePair += variableValue;
5542 setupParser("@-webkit-variables-decls{", nameValuePair, "} ");
5547 if (m_variableNames.size()) {
5549 declaration->addParsedVariable(variableName, m_variableValues[0]);
5554 #ifdef ANDROID_INSTRUMENT
5555 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
5560 void CSSParser::parsePropertyWithResolvedVariables(int propId, bool isImportant, CSSMutableStyleDeclaration* declaration, CSSParserValueList* list)
5563 m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
5565 if (parseValue(propId, isImportant))
5566 declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
5572 bool CSSParser::checkForVariables(CSSParserValueList* valueList)
5574 if (!valueList || !valueList->containsVariables())
5577 bool hasVariables = false;
5578 for (unsigned i = 0; i < valueList->size(); ++i) {
5579 if (valueList->valueAt(i)->isVariable()) {
5580 hasVariables = true;
5584 if (valueList->valueAt(i)->unit == CSSParserValue::Function && checkForVariables(valueList->valueAt(i)->function->args)) {
5585 hasVariables = true;
5590 return hasVariables;
5593 void CSSParser::addUnresolvedProperty(int propId, bool important)
5595 RefPtr<CSSVariableDependentValue> val = CSSVariableDependentValue::create(CSSValueList::createFromParserValueList(m_valueList));
5596 addProperty(propId, val.release(), important);
5599 void CSSParser::deleteFontFaceOnlyValues()
5601 ASSERT(m_hasFontFaceOnlyValues);
5602 int deletedProperties = 0;
5604 for (unsigned i = 0; i < m_numParsedProperties; ++i) {
5605 CSSProperty* property = m_parsedProperties[i];
5606 int id = property->id();
5607 if ((id == CSSPropertyFontWeight || id == CSSPropertyFontStyle || id == CSSPropertyFontVariant) && property->value()->isValueList()) {
5609 deletedProperties++;
5610 } else if (deletedProperties)
5611 m_parsedProperties[i - deletedProperties] = m_parsedProperties[i];
5614 m_numParsedProperties -= deletedProperties;
5617 WebKitCSSKeyframeRule* CSSParser::createKeyframeRule(CSSParserValueList* keys)
5619 // Create a key string from the passed keys
5621 for (unsigned i = 0; i < keys->size(); ++i) {
5622 float key = (float) keys->valueAt(i)->fValue;
5625 keyString += String::number(key);
5629 RefPtr<WebKitCSSKeyframeRule> keyframe = WebKitCSSKeyframeRule::create(m_styleSheet);
5630 keyframe->setKeyText(keyString);
5631 keyframe->setDeclaration(CSSMutableStyleDeclaration::create(0, m_parsedProperties, m_numParsedProperties));
5635 WebKitCSSKeyframeRule* keyframePtr = keyframe.get();
5636 m_parsedStyleObjects.append(keyframe.release());
5640 void CSSParser::invalidBlockHit()
5642 if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
5643 m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
5646 void CSSParser::updateLastSelectorLineAndPosition()
5648 m_lastSelectorLineNumber = m_lineNumber;
5649 markRuleBodyStart();
5652 void CSSParser::markRuleBodyStart()
5654 unsigned offset = yytext - m_data;
5655 if (!m_ruleBodyStartOffset || offset < m_ruleBodyStartOffset)
5656 m_ruleBodyStartOffset = offset;
5659 void CSSParser::markRuleBodyEnd()
5661 unsigned offset = yytext - m_data;
5662 if (offset > m_ruleBodyEndOffset)
5663 m_ruleBodyEndOffset = offset;
5666 static int cssPropertyID(const UChar* propertyName, unsigned length)
5670 if (length > maxCSSPropertyNameLength)
5673 char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
5675 for (unsigned i = 0; i != length; ++i) {
5676 UChar c = propertyName[i];
5677 if (c == 0 || c >= 0x7F)
5678 return 0; // illegal character
5679 buffer[i] = toASCIILower(c);
5681 buffer[length] = '\0';
5683 const char* name = buffer;
5684 if (buffer[0] == '-') {
5685 // If the prefix is -apple- or -khtml-, change it to -webkit-.
5686 // This makes the string one character longer.
5687 if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
5688 memmove(buffer + 7, buffer + 6, length + 1 - 6);
5689 memcpy(buffer, "-webkit", 7);
5693 if (hasPrefix(buffer, length, "-webkit")) {
5694 if (strcmp(buffer, "-webkit-opacity") == 0) {
5695 // Honor -webkit-opacity as a synonym for opacity.
5696 // This was the only syntax that worked in Safari 1.1, and may be in use on some websites and widgets.
5697 const char* const opacity = "opacity";
5699 length = strlen(opacity);
5700 } else if (hasPrefix(buffer + 7, length - 7, "-border-")) {
5701 // -webkit-border-*-*-radius worked in Safari 4 and earlier. -webkit-border-radius syntax
5702 // differs from border-radius, so it is remains as a distinct property.
5703 if (!strcmp(buffer + 15, "top-left-radius")
5704 || !strcmp(buffer + 15, "top-right-radius")
5705 || !strcmp(buffer + 15, "bottom-right-radius")
5706 || !strcmp(buffer + 15, "bottom-left-radius")) {
5714 const Property* hashTableEntry = findProperty(name, length);
5715 return hashTableEntry ? hashTableEntry->id : 0;
5718 int cssPropertyID(const String& string)
5720 return cssPropertyID(string.characters(), string.length());
5723 int cssPropertyID(const CSSParserString& string)
5725 return cssPropertyID(string.characters, string.length);
5728 int cssValueKeywordID(const CSSParserString& string)
5730 unsigned length = string.length;
5733 if (length > maxCSSValueKeywordLength)
5736 char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
5738 for (unsigned i = 0; i != length; ++i) {
5739 UChar c = string.characters[i];
5740 if (c == 0 || c >= 0x7F)
5741 return 0; // illegal character
5742 buffer[i] = WTF::toASCIILower(c);
5744 buffer[length] = '\0';
5746 if (buffer[0] == '-') {
5747 // If the prefix is -apple- or -khtml-, change it to -webkit-.
5748 // This makes the string one character longer.
5749 if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
5750 memmove(buffer + 7, buffer + 6, length + 1 - 6);
5751 memcpy(buffer, "-webkit", 7);
5756 const Value* hashTableEntry = findValue(buffer, length);
5757 return hashTableEntry ? hashTableEntry->id : 0;
5760 // "ident" from the CSS tokenizer, minus backslash-escape sequences
5761 static bool isCSSTokenizerIdentifier(const String& string)
5763 const UChar* p = string.characters();
5764 const UChar* end = p + string.length();
5767 if (p != end && p[0] == '-')
5771 if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p[0])))
5776 for (; p != end; ++p) {
5777 if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p[0])))
5784 // "url" from the CSS tokenizer, minus backslash-escape sequences
5785 static bool isCSSTokenizerURL(const String& string)
5787 const UChar* p = string.characters();
5788 const UChar* end = p + string.length();
5790 for (; p != end; ++p) {
5812 // We use single quotes for now because markup.cpp uses double quotes.
5813 String quoteCSSString(const String& string)
5815 // For efficiency, we first pre-calculate the length of the quoted string, then we build the actual one.
5816 // Please see below for the actual logic.
5817 unsigned quotedStringSize = 2; // Two quotes surrounding the entire string.
5818 bool afterEscape = false;
5819 for (unsigned i = 0; i < string.length(); ++i) {
5820 UChar ch = string[i];
5821 if (ch == '\\' || ch == '\'') {
5822 quotedStringSize += 2;
5823 afterEscape = false;
5824 } else if (ch < 0x20 || ch == 0x7F) {
5825 quotedStringSize += 2 + (ch >= 0x10);
5828 quotedStringSize += 1 + (afterEscape && (isASCIIHexDigit(ch) || ch == ' '));
5829 afterEscape = false;
5833 StringBuffer buffer(quotedStringSize);
5835 buffer[index++] = '\'';
5836 afterEscape = false;
5837 for (unsigned i = 0; i < string.length(); ++i) {
5838 UChar ch = string[i];
5839 if (ch == '\\' || ch == '\'') {
5840 buffer[index++] = '\\';
5841 buffer[index++] = ch;
5842 afterEscape = false;
5843 } else if (ch < 0x20 || ch == 0x7F) { // Control characters.
5844 static const char hexDigits[17] = "0123456789abcdef";
5845 buffer[index++] = '\\';
5847 buffer[index++] = hexDigits[ch >> 4];
5848 buffer[index++] = hexDigits[ch & 0xF];
5851 // Space character may be required to separate backslash-escape sequence and normal characters.
5852 if (afterEscape && (isASCIIHexDigit(ch) || ch == ' '))
5853 buffer[index++] = ' ';
5854 buffer[index++] = ch;
5855 afterEscape = false;
5858 buffer[index++] = '\'';
5860 ASSERT(quotedStringSize == index);
5861 return String::adopt(buffer);
5864 String quoteCSSStringIfNeeded(const String& string)
5866 return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string);
5869 String quoteCSSURLIfNeeded(const String& string)
5871 return isCSSTokenizerURL(string) ? string : quoteCSSString(string);
5874 #define YY_DECL int CSSParser::lex()
5875 #define yyconst const
5876 typedef int yy_state_type;
5877 typedef unsigned YY_CHAR;
5878 // The following line makes sure we treat non-Latin-1 Unicode characters correctly.
5879 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
5880 #define YY_DO_BEFORE_ACTION \
5882 yyleng = (int) (yy_cp - yy_bp); \
5883 yy_hold_char = *yy_cp; \
5886 #define YY_BREAK break;
5888 #define YY_RULE_SETUP
5890 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
5891 #define yyterminate() yyTok = END_TOKEN; return yyTok
5892 #define YY_FATAL_ERROR(a)
5893 // The following line is needed to build the tokenizer with a condition stack.
5894 // The macro is used in the tokenizer grammar with lines containing
5895 // BEGIN(mediaqueries) and BEGIN(initial). yy_start acts as index to
5896 // tokenizer transition table, and 'mediaqueries' and 'initial' are
5897 // offset multipliers that specify which transitions are active
5898 // in the tokenizer during in each condition (tokenizer state).
5899 #define BEGIN yy_start = 1 + 2 *
5901 #include "tokenizer.cpp"