--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WebCore/css/CSSParser.cpp Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,5842 @@
+/*
+ * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "CSSParser.h"
+
+#include "CSSTimingFunctionValue.h"
+#include "CSSBorderImageValue.h"
+#include "CSSCanvasValue.h"
+#include "CSSCharsetRule.h"
+#include "CSSCursorImageValue.h"
+#include "CSSHelper.h"
+#include "CSSImageValue.h"
+#include "CSSFontFaceRule.h"
+#include "CSSFontFaceSrcValue.h"
+#include "CSSGradientValue.h"
+#include "CSSImportRule.h"
+#include "CSSInheritedValue.h"
+#include "CSSInitialValue.h"
+#include "CSSMediaRule.h"
+#include "CSSMutableStyleDeclaration.h"
+#include "CSSPageRule.h"
+#include "CSSPrimitiveValue.h"
+#include "CSSProperty.h"
+#include "CSSPropertyNames.h"
+#include "CSSQuirkPrimitiveValue.h"
+#include "CSSReflectValue.h"
+#include "CSSRuleList.h"
+#include "CSSSelector.h"
+#include "CSSStyleRule.h"
+#include "CSSStyleSheet.h"
+#include "CSSUnicodeRangeValue.h"
+#include "CSSValueKeywords.h"
+#include "CSSValueList.h"
+#include "CSSVariableDependentValue.h"
+#include "CSSVariablesDeclaration.h"
+#include "CSSVariablesRule.h"
+#include "Counter.h"
+#include "Document.h"
+#include "FloatConversion.h"
+#include "FontFamilyValue.h"
+#include "FontValue.h"
+#include "MediaList.h"
+#include "MediaQueryExp.h"
+#include "Pair.h"
+#include "Rect.h"
+#include "ShadowValue.h"
+#include "StringBuffer.h"
+#include "WebKitCSSKeyframeRule.h"
+#include "WebKitCSSKeyframesRule.h"
+#include "WebKitCSSTransformValue.h"
+#include <limits.h>
+#include <wtf/dtoa.h>
+
+#if ENABLE(DASHBOARD_SUPPORT)
+#include "DashboardRegion.h"
+#endif
+
+#define YYDEBUG 0
+
+#if YYDEBUG > 0
+extern int cssyydebug;
+#endif
+
+extern int cssyyparse(void* parser);
+
+using namespace std;
+using namespace WTF;
+
+#include "CSSPropertyNames.cpp"
+#include "CSSValueKeywords.cpp"
+
+namespace WebCore {
+
+static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
+
+static bool equal(const CSSParserString& a, const char* b)
+{
+ for (int i = 0; i < a.length; ++i) {
+ if (!b[i])
+ return false;
+ if (a.characters[i] != b[i])
+ return false;
+ }
+ return !b[a.length];
+}
+
+static bool equalIgnoringCase(const CSSParserString& a, const char* b)
+{
+ for (int i = 0; i < a.length; ++i) {
+ if (!b[i])
+ return false;
+ ASSERT(!isASCIIUpper(b[i]));
+ if (toASCIILower(a.characters[i]) != b[i])
+ return false;
+ }
+ return !b[a.length];
+}
+
+static bool hasPrefix(const char* string, unsigned length, const char* prefix)
+{
+ for (unsigned i = 0; i < length; ++i) {
+ if (!prefix[i])
+ return true;
+ if (string[i] != prefix[i])
+ return false;
+ }
+ return false;
+}
+
+CSSParser::CSSParser(bool strictParsing)
+ : m_strict(strictParsing)
+ , m_important(false)
+ , m_id(0)
+ , m_styleSheet(0)
+ , m_mediaQuery(0)
+ , m_valueList(0)
+ , m_parsedProperties(static_cast<CSSProperty**>(fastMalloc(32 * sizeof(CSSProperty*))))
+ , m_numParsedProperties(0)
+ , m_maxParsedProperties(32)
+ , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
+ , m_inParseShorthand(0)
+ , m_currentShorthand(0)
+ , m_implicitShorthand(false)
+ , m_hasFontFaceOnlyValues(false)
+ , m_hadSyntacticallyValidCSSRule(false)
+ , m_defaultNamespace(starAtom)
+ , m_ruleBodyStartOffset(0)
+ , m_ruleBodyEndOffset(0)
+ , m_ruleRanges(0)
+ , m_data(0)
+ , yy_start(1)
+ , m_lineNumber(0)
+ , m_lastSelectorLineNumber(0)
+ , m_allowImportRules(true)
+ , m_allowVariablesRules(true)
+ , m_allowNamespaceDeclarations(true)
+ , m_floatingMediaQuery(0)
+ , m_floatingMediaQueryExp(0)
+ , m_floatingMediaQueryExpList(0)
+{
+#if YYDEBUG > 0
+ cssyydebug = 1;
+#endif
+}
+
+CSSParser::~CSSParser()
+{
+ clearProperties();
+ fastFree(m_parsedProperties);
+
+ clearVariables();
+
+ delete m_valueList;
+
+ fastFree(m_data);
+
+ if (m_floatingMediaQueryExpList) {
+ deleteAllValues(*m_floatingMediaQueryExpList);
+ delete m_floatingMediaQueryExpList;
+ }
+ delete m_floatingMediaQueryExp;
+ delete m_floatingMediaQuery;
+ fastDeleteAllValues(m_floatingSelectors);
+ deleteAllValues(m_floatingValueLists);
+ deleteAllValues(m_floatingFunctions);
+ deleteAllValues(m_reusableSelectorVector);
+}
+
+void CSSParserString::lower()
+{
+ // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
+ // that can potentially change the length of the string rather than the character
+ // by character kind. If we don't need Unicode lowercasing, it would be good to
+ // simplify this function.
+
+ if (charactersAreAllASCII(characters, length)) {
+ // Fast case for all-ASCII.
+ for (int i = 0; i < length; i++)
+ characters[i] = toASCIILower(characters[i]);
+ } else {
+ for (int i = 0; i < length; i++)
+ characters[i] = Unicode::toLower(characters[i]);
+ }
+}
+
+void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix)
+{
+ int length = string.length() + strlen(prefix) + strlen(suffix) + 2;
+
+ fastFree(m_data);
+ m_data = static_cast<UChar*>(fastMalloc(length * sizeof(UChar)));
+ for (unsigned i = 0; i < strlen(prefix); i++)
+ m_data[i] = prefix[i];
+
+ memcpy(m_data + strlen(prefix), string.characters(), string.length() * sizeof(UChar));
+
+ unsigned start = strlen(prefix) + string.length();
+ unsigned end = start + strlen(suffix);
+ for (unsigned i = start; i < end; i++)
+ m_data[i] = suffix[i - start];
+
+ m_data[length - 1] = 0;
+ m_data[length - 2] = 0;
+
+ yy_hold_char = 0;
+ yyleng = 0;
+ yytext = yy_c_buf_p = m_data;
+ yy_hold_char = *yy_c_buf_p;
+ resetRuleBodyMarks();
+}
+
+void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string, int startLineNumber, StyleRuleRanges* ruleRangeMap)
+{
+ m_styleSheet = sheet;
+ m_defaultNamespace = starAtom; // Reset the default namespace.
+ m_ruleRanges = ruleRangeMap;
+
+ m_lineNumber = startLineNumber;
+ setupParser("", string, "");
+ cssyyparse(this);
+ m_ruleRanges = 0;
+ m_rule = 0;
+}
+
+PassRefPtr<CSSRule> CSSParser::parseRule(CSSStyleSheet* sheet, const String& string)
+{
+ m_styleSheet = sheet;
+ m_allowNamespaceDeclarations = false;
+ setupParser("@-webkit-rule{", string, "} ");
+ cssyyparse(this);
+ return m_rule.release();
+}
+
+PassRefPtr<CSSRule> CSSParser::parseKeyframeRule(CSSStyleSheet *sheet, const String &string)
+{
+ m_styleSheet = sheet;
+ setupParser("@-webkit-keyframe-rule{ ", string, "} ");
+ cssyyparse(this);
+ return m_keyframe.release();
+}
+
+bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int id, const String& string, bool important)
+{
+ ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
+ m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
+
+ setupParser("@-webkit-value{", string, "} ");
+
+ m_id = id;
+ m_important = important;
+
+ cssyyparse(this);
+
+ m_rule = 0;
+
+ bool ok = false;
+ if (m_hasFontFaceOnlyValues)
+ deleteFontFaceOnlyValues();
+ if (m_numParsedProperties) {
+ ok = true;
+ declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
+ clearProperties();
+ }
+
+ return ok;
+}
+
+// color will only be changed when string contains a valid css color, making it
+// possible to set up a default color.
+bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
+{
+ // First try creating a color specified by name, rgb() or "#" syntax.
+ if (parseColor(string, color, strict))
+ return true;
+
+ CSSParser parser(true);
+ RefPtr<CSSMutableStyleDeclaration> dummyStyleDeclaration = CSSMutableStyleDeclaration::create();
+
+ // Now try to create a color from rgba() syntax.
+ if (!parser.parseColor(dummyStyleDeclaration.get(), string))
+ return false;
+
+ CSSValue* value = parser.m_parsedProperties[0]->value();
+ if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) {
+ CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
+ color = primitiveValue->getRGBA32Value();
+ }
+
+ return true;
+}
+
+bool CSSParser::parseColor(CSSMutableStyleDeclaration* declaration, const String& string)
+{
+ ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
+ m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
+
+ setupParser("@-webkit-decls{color:", string, "} ");
+ cssyyparse(this);
+ m_rule = 0;
+
+ return (m_numParsedProperties && m_parsedProperties[0]->m_id == CSSPropertyColor);
+}
+
+void CSSParser::parseSelector(const String& string, Document* doc, CSSSelectorList& selectorList)
+{
+ RefPtr<CSSStyleSheet> dummyStyleSheet = CSSStyleSheet::create(doc);
+
+ m_styleSheet = dummyStyleSheet.get();
+ m_selectorListForParseSelector = &selectorList;
+
+ setupParser("@-webkit-selector{", string, "}");
+
+ cssyyparse(this);
+
+ m_selectorListForParseSelector = 0;
+}
+
+bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration* declaration, const String& string)
+{
+ ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
+ m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
+
+ setupParser("@-webkit-decls{", string, "} ");
+ cssyyparse(this);
+ m_rule = 0;
+
+ bool ok = false;
+ if (m_hasFontFaceOnlyValues)
+ deleteFontFaceOnlyValues();
+ if (m_numParsedProperties) {
+ ok = true;
+ declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
+ clearProperties();
+ }
+
+ return ok;
+}
+
+bool CSSParser::parseMediaQuery(MediaList* queries, const String& string)
+{
+ if (string.isEmpty())
+ return true;
+
+ m_mediaQuery = 0;
+ // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
+ // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
+ setupParser("@-webkit-mediaquery ", string, "} ");
+ cssyyparse(this);
+
+ bool ok = false;
+ if (m_mediaQuery) {
+ ok = true;
+ queries->appendMediaQuery(m_mediaQuery);
+ m_mediaQuery = 0;
+ }
+
+ return ok;
+}
+
+
+void CSSParser::addProperty(int propId, PassRefPtr<CSSValue> value, bool important)
+{
+ OwnPtr<CSSProperty> prop(new CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand));
+ if (m_numParsedProperties >= m_maxParsedProperties) {
+ m_maxParsedProperties += 32;
+ if (m_maxParsedProperties > UINT_MAX / sizeof(CSSProperty*))
+ return;
+ m_parsedProperties = static_cast<CSSProperty**>(fastRealloc(m_parsedProperties,
+ m_maxParsedProperties * sizeof(CSSProperty*)));
+ }
+ m_parsedProperties[m_numParsedProperties++] = prop.leakPtr();
+}
+
+void CSSParser::rollbackLastProperties(int num)
+{
+ ASSERT(num >= 0);
+ ASSERT(m_numParsedProperties >= static_cast<unsigned>(num));
+
+ for (int i = 0; i < num; ++i)
+ delete m_parsedProperties[--m_numParsedProperties];
+}
+
+void CSSParser::clearProperties()
+{
+ for (unsigned i = 0; i < m_numParsedProperties; i++)
+ delete m_parsedProperties[i];
+ m_numParsedProperties = 0;
+ m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
+ m_hasFontFaceOnlyValues = false;
+}
+
+Document* CSSParser::document() const
+{
+ StyleBase* root = m_styleSheet;
+ Document* doc = 0;
+ while (root && root->parent())
+ root = root->parent();
+ if (root && root->isCSSStyleSheet())
+ doc = static_cast<CSSStyleSheet*>(root)->doc();
+ return doc;
+}
+
+bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, bool strict)
+{
+ bool b = false;
+ switch (value->unit) {
+ case CSSPrimitiveValue::CSS_NUMBER:
+ b = (unitflags & FNumber);
+ if (!b && ((unitflags & (FLength | FAngle | FTime)) && (value->fValue == 0 || !strict))) {
+ value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
+ ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
+ b = true;
+ }
+ if (!b && (unitflags & FInteger) && value->isInt)
+ b = true;
+ break;
+ case CSSPrimitiveValue::CSS_PERCENTAGE:
+ b = (unitflags & FPercent);
+ break;
+ case CSSParserValue::Q_EMS:
+ case CSSPrimitiveValue::CSS_EMS:
+ case CSSPrimitiveValue::CSS_REMS:
+ case CSSPrimitiveValue::CSS_EXS:
+ case CSSPrimitiveValue::CSS_PX:
+ case CSSPrimitiveValue::CSS_CM:
+ case CSSPrimitiveValue::CSS_MM:
+ case CSSPrimitiveValue::CSS_IN:
+ case CSSPrimitiveValue::CSS_PT:
+ case CSSPrimitiveValue::CSS_PC:
+ b = (unitflags & FLength);
+ break;
+ case CSSPrimitiveValue::CSS_MS:
+ case CSSPrimitiveValue::CSS_S:
+ b = (unitflags & FTime);
+ break;
+ case CSSPrimitiveValue::CSS_DEG:
+ case CSSPrimitiveValue::CSS_RAD:
+ case CSSPrimitiveValue::CSS_GRAD:
+ case CSSPrimitiveValue::CSS_TURN:
+ b = (unitflags & FAngle);
+ break;
+ case CSSPrimitiveValue::CSS_HZ:
+ case CSSPrimitiveValue::CSS_KHZ:
+ case CSSPrimitiveValue::CSS_DIMENSION:
+ default:
+ break;
+ }
+ if (b && unitflags & FNonNeg && value->fValue < 0)
+ b = false;
+ return b;
+}
+
+static int unitFromString(CSSParserValue* value)
+{
+ if (value->unit != CSSPrimitiveValue::CSS_IDENT || value->id)
+ return 0;
+
+ if (equal(value->string, "em"))
+ return CSSPrimitiveValue::CSS_EMS;
+ if (equal(value->string, "rem"))
+ return CSSPrimitiveValue::CSS_REMS;
+ if (equal(value->string, "ex"))
+ return CSSPrimitiveValue::CSS_EXS;
+ if (equal(value->string, "px"))
+ return CSSPrimitiveValue::CSS_PX;
+ if (equal(value->string, "cm"))
+ return CSSPrimitiveValue::CSS_CM;
+ if (equal(value->string, "mm"))
+ return CSSPrimitiveValue::CSS_MM;
+ if (equal(value->string, "in"))
+ return CSSPrimitiveValue::CSS_IN;
+ if (equal(value->string, "pt"))
+ return CSSPrimitiveValue::CSS_PT;
+ if (equal(value->string, "pc"))
+ return CSSPrimitiveValue::CSS_PC;
+ if (equal(value->string, "deg"))
+ return CSSPrimitiveValue::CSS_DEG;
+ if (equal(value->string, "rad"))
+ return CSSPrimitiveValue::CSS_RAD;
+ if (equal(value->string, "grad"))
+ return CSSPrimitiveValue::CSS_GRAD;
+ if (equal(value->string, "turn"))
+ return CSSPrimitiveValue::CSS_TURN;
+ if (equal(value->string, "ms"))
+ return CSSPrimitiveValue::CSS_MS;
+ if (equal(value->string, "s"))
+ return CSSPrimitiveValue::CSS_S;
+ if (equal(value->string, "Hz"))
+ return CSSPrimitiveValue::CSS_HZ;
+ if (equal(value->string, "kHz"))
+ return CSSPrimitiveValue::CSS_KHZ;
+
+ return 0;
+}
+
+void CSSParser::checkForOrphanedUnits()
+{
+ if (m_strict || inShorthand())
+ return;
+
+ // The purpose of this code is to implement the WinIE quirk that allows unit types to be separated from their numeric values
+ // 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.
+ CSSParserValue* numericVal = 0;
+ unsigned size = m_valueList->size();
+ for (unsigned i = 0; i < size; i++) {
+ CSSParserValue* value = m_valueList->valueAt(i);
+
+ if (numericVal) {
+ // Change the unit type of the numeric val to match.
+ int unit = unitFromString(value);
+ if (unit) {
+ numericVal->unit = unit;
+ numericVal = 0;
+
+ // Now delete the bogus unit value.
+ m_valueList->deleteValueAt(i);
+ 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).
+ size--;
+ continue;
+ }
+ }
+
+ numericVal = (value->unit == CSSPrimitiveValue::CSS_NUMBER) ? value : 0;
+ }
+}
+
+bool CSSParser::parseValue(int propId, bool important)
+{
+ if (!m_valueList)
+ return false;
+
+ CSSParserValue *value = m_valueList->current();
+
+ if (!value)
+ return false;
+
+ int id = value->id;
+
+ // In quirks mode, we will look for units that have been incorrectly separated from the number they belong to
+ // by a space. We go ahead and associate the unit with the number even though it is invalid CSS.
+ checkForOrphanedUnits();
+
+ int num = inShorthand() ? 1 : m_valueList->size();
+
+ if (id == CSSValueInherit) {
+ if (num != 1)
+ return false;
+ addProperty(propId, CSSInheritedValue::create(), important);
+ return true;
+ }
+ else if (id == CSSValueInitial) {
+ if (num != 1)
+ return false;
+ addProperty(propId, CSSInitialValue::createExplicit(), important);
+ return true;
+ }
+
+ // If we have any variables, then we don't parse the list of values yet. We add them to the declaration
+ // as unresolved, and allow them to be parsed later. The parse is considered "successful" for now, even though
+ // it might ultimately fail once the variable has been resolved.
+ if (!inShorthand() && checkForVariables(m_valueList)) {
+ addUnresolvedProperty(propId, important);
+ return true;
+ }
+
+ bool validPrimitive = false;
+ RefPtr<CSSValue> parsedValue;
+
+ switch (static_cast<CSSPropertyID>(propId)) {
+ /* The comment to the left defines all valid value of this properties as defined
+ * in CSS 2, Appendix F. Property index
+ */
+
+ /* All the CSS properties are not supported by the renderer at the moment.
+ * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
+ * (see parseAuralValues). As we don't support them at all this seems reasonable.
+ */
+
+ case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
+ return parseSize(propId, important);
+
+ case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit
+ if (id)
+ validPrimitive = true;
+ break;
+ case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | inherit
+ if (id == CSSValueNormal ||
+ id == CSSValueEmbed ||
+ id == CSSValueBidiOverride)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyPosition: // static | relative | absolute | fixed | inherit
+ if (id == CSSValueStatic ||
+ id == CSSValueRelative ||
+ id == CSSValueAbsolute ||
+ id == CSSValueFixed)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit
+ case CSSPropertyPageBreakBefore:
+ case CSSPropertyWebkitColumnBreakAfter:
+ case CSSPropertyWebkitColumnBreakBefore:
+ if (id == CSSValueAuto ||
+ id == CSSValueAlways ||
+ id == CSSValueAvoid ||
+ id == CSSValueLeft ||
+ id == CSSValueRight)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyPageBreakInside: // avoid | auto | inherit
+ case CSSPropertyWebkitColumnBreakInside:
+ if (id == CSSValueAuto || id == CSSValueAvoid)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyEmptyCells: // show | hide | inherit
+ if (id == CSSValueShow ||
+ id == CSSValueHide)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
+ // close-quote | no-open-quote | no-close-quote ]+ | inherit
+ return parseContent(propId, important);
+
+ case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit
+ if (id == CSSValueNormal ||
+ id == CSSValuePre ||
+ id == CSSValuePreWrap ||
+ id == CSSValuePreLine ||
+ id == CSSValueNowrap)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyClip: // <shape> | auto | inherit
+ if (id == CSSValueAuto)
+ validPrimitive = true;
+ else if (value->unit == CSSParserValue::Function)
+ return parseShape(propId, important);
+ break;
+
+ /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
+ * correctly and allows optimization in WebCore::applyRule(..)
+ */
+ case CSSPropertyCaptionSide: // top | bottom | left | right | inherit
+ if (id == CSSValueLeft || id == CSSValueRight ||
+ id == CSSValueTop || id == CSSValueBottom)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyBorderCollapse: // collapse | separate | inherit
+ if (id == CSSValueCollapse || id == CSSValueSeparate)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyVisibility: // visible | hidden | collapse | inherit
+ if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueCollapse)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyOverflow: {
+ ShorthandScope scope(this, propId);
+ if (num != 1 || !parseValue(CSSPropertyOverflowX, important))
+ return false;
+ CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value();
+ addProperty(CSSPropertyOverflowY, value, important);
+ return true;
+ }
+ case CSSPropertyOverflowX:
+ case CSSPropertyOverflowY: // visible | hidden | scroll | auto | marquee | overlay | inherit
+ if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueScroll || id == CSSValueAuto ||
+ id == CSSValueOverlay || id == CSSValueWebkitMarquee)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyListStylePosition: // inside | outside | inherit
+ if (id == CSSValueInside || id == CSSValueOutside)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyListStyleType:
+ // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
+ // for the list of supported list-style-types.
+ if ((id >= CSSValueDisc && id <= CSSValueKatakanaIroha) || id == CSSValueNone)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyDisplay:
+ // inline | block | list-item | run-in | inline-block | table |
+ // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
+ // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit
+#if ENABLE(WCSS)
+ if ((id >= CSSValueInline && id <= CSSValueWapMarquee) || id == CSSValueNone)
+#else
+ if ((id >= CSSValueInline && id <= CSSValueWebkitInlineBox) || id == CSSValueNone)
+#endif
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyDirection: // ltr | rtl | inherit
+ if (id == CSSValueLtr || id == CSSValueRtl)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit
+ if ((id >= CSSValueCapitalize && id <= CSSValueLowercase) || id == CSSValueNone)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyFloat: // left | right | none | inherit + center for buggy CSS
+ if (id == CSSValueLeft || id == CSSValueRight ||
+ id == CSSValueNone || id == CSSValueCenter)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyClear: // none | left | right | both | inherit
+ if (id == CSSValueNone || id == CSSValueLeft ||
+ id == CSSValueRight|| id == CSSValueBoth)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyTextAlign:
+ // left | right | center | justify | webkit_left | webkit_right | webkit_center | start | end | <string> | inherit
+ if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitCenter) || id == CSSValueStart || id == CSSValueEnd ||
+ value->unit == CSSPrimitiveValue::CSS_STRING)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit
+ if (id == CSSValueAuto || id == CSSValueNone || (id >= CSSValueInset && id <= CSSValueDouble))
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyBorderTopStyle: //// <border-style> | inherit
+ case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
+ case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
+ case CSSPropertyBorderLeftStyle:
+ case CSSPropertyWebkitBorderStartStyle:
+ case CSSPropertyWebkitBorderEndStyle:
+ case CSSPropertyWebkitColumnRuleStyle:
+ if (id >= CSSValueNone && id <= CSSValueDouble)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyFontWeight: // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
+ return parseFontWeight(important);
+
+ case CSSPropertyBorderSpacing: {
+ const int properties[2] = { CSSPropertyWebkitBorderHorizontalSpacing,
+ CSSPropertyWebkitBorderVerticalSpacing };
+ if (num == 1) {
+ ShorthandScope scope(this, CSSPropertyBorderSpacing);
+ if (!parseValue(properties[0], important))
+ return false;
+ CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value();
+ addProperty(properties[1], value, important);
+ return true;
+ }
+ else if (num == 2) {
+ ShorthandScope scope(this, CSSPropertyBorderSpacing);
+ if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
+ return false;
+ return true;
+ }
+ return false;
+ }
+ case CSSPropertyWebkitBorderHorizontalSpacing:
+ case CSSPropertyWebkitBorderVerticalSpacing:
+ validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
+ break;
+ case CSSPropertyOutlineColor: // <color> | invert | inherit
+ // Outline color has "invert" as additional keyword.
+ // Also, we want to allow the special focus color even in strict parsing mode.
+ if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
+ validPrimitive = true;
+ break;
+ }
+ /* nobreak */
+ case CSSPropertyBackgroundColor: // <color> | inherit
+ case CSSPropertyBorderTopColor: // <color> | inherit
+ case CSSPropertyBorderRightColor:
+ case CSSPropertyBorderBottomColor:
+ case CSSPropertyBorderLeftColor:
+ case CSSPropertyWebkitBorderStartColor:
+ case CSSPropertyWebkitBorderEndColor:
+ case CSSPropertyColor: // <color> | inherit
+ case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors
+ case CSSPropertyTextUnderlineColor:
+ case CSSPropertyTextOverlineColor:
+ case CSSPropertyWebkitColumnRuleColor:
+ case CSSPropertyWebkitTextFillColor:
+ case CSSPropertyWebkitTextStrokeColor:
+ if (id == CSSValueWebkitText)
+ validPrimitive = true; // Always allow this, even when strict parsing is on,
+ // since we use this in our UA sheets.
+ else if (id == CSSValueCurrentcolor)
+ validPrimitive = true;
+ else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu ||
+ (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && !m_strict)) {
+ validPrimitive = true;
+ } else {
+ parsedValue = parseColor();
+ if (parsedValue)
+ m_valueList->next();
+ }
+ break;
+
+ case CSSPropertyCursor: {
+ // [<uri>,]* [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
+ // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
+ // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
+ // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
+ // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
+ RefPtr<CSSValueList> list;
+ while (value && value->unit == CSSPrimitiveValue::CSS_URI) {
+ if (!list)
+ list = CSSValueList::createCommaSeparated();
+ String uri = value->string;
+ Vector<int> coords;
+ value = m_valueList->next();
+ while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
+ coords.append(int(value->fValue));
+ value = m_valueList->next();
+ }
+ IntPoint hotSpot(-1, -1);
+ int nrcoords = coords.size();
+ if (nrcoords > 0 && nrcoords != 2)
+ return false;
+ if (nrcoords == 2)
+ hotSpot = IntPoint(coords[0], coords[1]);
+
+ if (!uri.isNull() && m_styleSheet) {
+ // FIXME: The completeURL call should be done when using the CSSCursorImageValue,
+ // not when creating it.
+ list->append(CSSCursorImageValue::create(m_styleSheet->completeURL(uri), hotSpot));
+ }
+
+ if ((m_strict && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ',')))
+ return false;
+ value = m_valueList->next(); // comma
+ }
+ if (list) {
+ if (!value) { // no value after url list (MSIE 5 compatibility)
+ if (list->length() != 1)
+ return false;
+ } else if (!m_strict && value->id == CSSValueHand) // MSIE 5 compatibility :/
+ list->append(CSSPrimitiveValue::createIdentifier(CSSValuePointer));
+ else if (value && ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone))
+ list->append(CSSPrimitiveValue::createIdentifier(value->id));
+ m_valueList->next();
+ parsedValue = list.release();
+ break;
+ }
+ id = value->id;
+ if (!m_strict && value->id == CSSValueHand) { // MSIE 5 compatibility :/
+ id = CSSValuePointer;
+ validPrimitive = true;
+ } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
+ validPrimitive = true;
+ break;
+ }
+
+ case CSSPropertyBackgroundAttachment:
+ case CSSPropertyBackgroundClip:
+ case CSSPropertyWebkitBackgroundClip:
+ case CSSPropertyWebkitBackgroundComposite:
+ case CSSPropertyBackgroundImage:
+ case CSSPropertyBackgroundOrigin:
+ case CSSPropertyWebkitBackgroundOrigin:
+ case CSSPropertyBackgroundPosition:
+ case CSSPropertyBackgroundPositionX:
+ case CSSPropertyBackgroundPositionY:
+ case CSSPropertyBackgroundSize:
+ case CSSPropertyWebkitBackgroundSize:
+ case CSSPropertyBackgroundRepeat:
+ case CSSPropertyBackgroundRepeatX:
+ case CSSPropertyBackgroundRepeatY:
+ case CSSPropertyWebkitMaskAttachment:
+ case CSSPropertyWebkitMaskClip:
+ case CSSPropertyWebkitMaskComposite:
+ case CSSPropertyWebkitMaskImage:
+ case CSSPropertyWebkitMaskOrigin:
+ case CSSPropertyWebkitMaskPosition:
+ case CSSPropertyWebkitMaskPositionX:
+ case CSSPropertyWebkitMaskPositionY:
+ case CSSPropertyWebkitMaskSize:
+ case CSSPropertyWebkitMaskRepeat:
+ case CSSPropertyWebkitMaskRepeatX:
+ case CSSPropertyWebkitMaskRepeatY: {
+ RefPtr<CSSValue> val1;
+ RefPtr<CSSValue> val2;
+ int propId1, propId2;
+ bool result = false;
+ if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
+ OwnPtr<ShorthandScope> shorthandScope;
+ if (propId == CSSPropertyBackgroundPosition ||
+ propId == CSSPropertyBackgroundRepeat ||
+ propId == CSSPropertyWebkitMaskPosition ||
+ propId == CSSPropertyWebkitMaskRepeat) {
+ shorthandScope.set(new ShorthandScope(this, propId));
+ }
+ addProperty(propId1, val1.release(), important);
+ if (val2)
+ addProperty(propId2, val2.release(), important);
+ result = true;
+ }
+ m_implicitShorthand = false;
+ return result;
+ }
+ case CSSPropertyListStyleImage: // <uri> | none | inherit
+ if (id == CSSValueNone) {
+ parsedValue = CSSImageValue::create();
+ m_valueList->next();
+ } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
+ if (m_styleSheet) {
+ // FIXME: The completeURL call should be done when using the CSSImageValue,
+ // not when creating it.
+ parsedValue = CSSImageValue::create(m_styleSheet->completeURL(value->string));
+ m_valueList->next();
+ }
+ } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-gradient(")) {
+ if (parseGradient(parsedValue))
+ m_valueList->next();
+ else
+ return false;
+ }
+ break;
+
+ case CSSPropertyWebkitTextStrokeWidth:
+ case CSSPropertyOutlineWidth: // <border-width> | inherit
+ case CSSPropertyBorderTopWidth: //// <border-width> | inherit
+ case CSSPropertyBorderRightWidth: // Which is defined as
+ case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
+ case CSSPropertyBorderLeftWidth:
+ case CSSPropertyWebkitBorderStartWidth:
+ case CSSPropertyWebkitBorderEndWidth:
+ case CSSPropertyWebkitColumnRuleWidth:
+ if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
+ validPrimitive = true;
+ else
+ validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
+ break;
+
+ case CSSPropertyLetterSpacing: // normal | <length> | inherit
+ case CSSPropertyWordSpacing: // normal | <length> | inherit
+ if (id == CSSValueNormal)
+ validPrimitive = true;
+ else
+ validPrimitive = validUnit(value, FLength, m_strict);
+ break;
+
+ case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
+ if (id == CSSValueNormal || id == CSSValueBreakAll || id == CSSValueBreakWord)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyWordWrap: // normal | break-word
+ if (id == CSSValueNormal || id == CSSValueBreakWord)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyTextIndent: // <length> | <percentage> | inherit
+ validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
+ break;
+
+ case CSSPropertyPaddingTop: //// <padding-width> | inherit
+ case CSSPropertyPaddingRight: // Which is defined as
+ case CSSPropertyPaddingBottom: // <length> | <percentage>
+ case CSSPropertyPaddingLeft: ////
+ case CSSPropertyWebkitPaddingStart:
+ case CSSPropertyWebkitPaddingEnd:
+ validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
+ break;
+
+ case CSSPropertyMaxHeight: // <length> | <percentage> | none | inherit
+ case CSSPropertyMaxWidth: // <length> | <percentage> | none | inherit
+ if (id == CSSValueNone || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) {
+ validPrimitive = true;
+ break;
+ }
+ /* nobreak */
+ case CSSPropertyMinHeight: // <length> | <percentage> | inherit
+ case CSSPropertyMinWidth: // <length> | <percentage> | inherit
+ if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
+ validPrimitive = true;
+ else
+ validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
+ break;
+
+ case CSSPropertyFontSize:
+ // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
+ if (id >= CSSValueXxSmall && id <= CSSValueLarger)
+ validPrimitive = true;
+ else
+ validPrimitive = (validUnit(value, FLength | FPercent | FNonNeg, m_strict));
+ break;
+
+ case CSSPropertyFontStyle: // normal | italic | oblique | inherit
+ return parseFontStyle(important);
+
+ case CSSPropertyFontVariant: // normal | small-caps | inherit
+ return parseFontVariant(important);
+
+ case CSSPropertyVerticalAlign:
+ // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
+ // <percentage> | <length> | inherit
+
+ if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
+ validPrimitive = true;
+ else
+ validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
+ break;
+
+ case CSSPropertyHeight: // <length> | <percentage> | auto | inherit
+ case CSSPropertyWidth: // <length> | <percentage> | auto | inherit
+ if (id == CSSValueAuto || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
+ validPrimitive = true;
+ else
+ // ### handle multilength case where we allow relative units
+ validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
+ break;
+
+ case CSSPropertyBottom: // <length> | <percentage> | auto | inherit
+ case CSSPropertyLeft: // <length> | <percentage> | auto | inherit
+ case CSSPropertyRight: // <length> | <percentage> | auto | inherit
+ case CSSPropertyTop: // <length> | <percentage> | auto | inherit
+ case CSSPropertyMarginTop: //// <margin-width> | inherit
+ case CSSPropertyMarginRight: // Which is defined as
+ case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit
+ case CSSPropertyMarginLeft: ////
+ case CSSPropertyWebkitMarginStart:
+ case CSSPropertyWebkitMarginEnd:
+ if (id == CSSValueAuto)
+ validPrimitive = true;
+ else
+ validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
+ break;
+
+ case CSSPropertyZIndex: // auto | <integer> | inherit
+ if (id == CSSValueAuto) {
+ validPrimitive = true;
+ break;
+ }
+ /* nobreak */
+ case CSSPropertyOrphans: // <integer> | inherit
+ case CSSPropertyWidows: // <integer> | inherit
+ // ### not supported later on
+ validPrimitive = (!id && validUnit(value, FInteger, false));
+ break;
+
+ case CSSPropertyLineHeight: // normal | <number> | <length> | <percentage> | inherit
+ if (id == CSSValueNormal)
+ validPrimitive = true;
+ else
+ validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict));
+ break;
+ case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
+ if (id != CSSValueNone)
+ return parseCounter(propId, 1, important);
+ validPrimitive = true;
+ break;
+ case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit
+ if (id != CSSValueNone)
+ return parseCounter(propId, 0, important);
+ validPrimitive = true;
+ break;
+ case CSSPropertyFontFamily:
+ // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
+ {
+ parsedValue = parseFontFamily();
+ break;
+ }
+
+ case CSSPropertyTextDecoration:
+ case CSSPropertyWebkitTextDecorationsInEffect:
+ // none | [ underline || overline || line-through || blink ] | inherit
+ if (id == CSSValueNone) {
+ validPrimitive = true;
+ } else {
+ RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
+ bool isValid = true;
+ while (isValid && value) {
+ switch (value->id) {
+ case CSSValueBlink:
+ break;
+ case CSSValueUnderline:
+ case CSSValueOverline:
+ case CSSValueLineThrough:
+ list->append(CSSPrimitiveValue::createIdentifier(value->id));
+ break;
+ default:
+ isValid = false;
+ }
+ value = m_valueList->next();
+ }
+ if (list->length() && isValid) {
+ parsedValue = list.release();
+ m_valueList->next();
+ }
+ }
+ break;
+
+ case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit
+ if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
+ validPrimitive = true;
+ else
+ validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, true));
+ break;
+
+ case CSSPropertyTableLayout: // auto | fixed | inherit
+ if (id == CSSValueAuto || id == CSSValueFixed)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertySrc: // Only used within @font-face, so cannot use inherit | initial or be !important. This is a list of urls or local references.
+ return parseFontFaceSrc();
+
+ case CSSPropertyUnicodeRange:
+ return parseFontFaceUnicodeRange();
+
+ /* CSS3 properties */
+ case CSSPropertyWebkitAppearance:
+ if ((id >= CSSValueCheckbox && id <= CSSValueTextarea) || id == CSSValueNone)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyWebkitBinding:
+#if ENABLE(XBL)
+ if (id == CSSValueNone)
+ validPrimitive = true;
+ else {
+ RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
+ CSSParserValue* val;
+ RefPtr<CSSValue> parsedValue;
+ while ((val = m_valueList->current())) {
+ if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
+ // FIXME: The completeURL call should be done when using the CSSPrimitiveValue,
+ // not when creating it.
+ parsedValue = CSSPrimitiveValue::create(m_styleSheet->completeURL(val->string), CSSPrimitiveValue::CSS_URI);
+ }
+ if (!parsedValue)
+ break;
+
+ // FIXME: We can't use release() here since we might hit this path twice
+ // but that logic seems wrong to me to begin with, we convert all non-uri values
+ // into the last seen URI value!?
+ // -webkit-binding: url(foo.xml), 1, 2; (if that were valid) is treated as:
+ // -webkit-binding: url(foo.xml), url(foo.xml), url(foo.xml); !?
+ values->append(parsedValue.get());
+ m_valueList->next();
+ }
+ if (!values->length())
+ return false;
+
+ addProperty(propId, values.release(), important);
+ m_valueList->next();
+ return true;
+ }
+#endif
+ break;
+ case CSSPropertyWebkitBorderImage:
+ case CSSPropertyWebkitMaskBoxImage:
+ if (id == CSSValueNone)
+ validPrimitive = true;
+ else {
+ RefPtr<CSSValue> result;
+ if (parseBorderImage(propId, important, result)) {
+ addProperty(propId, result, important);
+ return true;
+ }
+ }
+ break;
+ case CSSPropertyBorderTopRightRadius:
+ case CSSPropertyBorderTopLeftRadius:
+ case CSSPropertyBorderBottomLeftRadius:
+ case CSSPropertyBorderBottomRightRadius: {
+ if (num != 1 && num != 2)
+ return false;
+ validPrimitive = validUnit(value, FLength, m_strict);
+ if (!validPrimitive)
+ return false;
+ RefPtr<CSSPrimitiveValue> parsedValue1 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
+ RefPtr<CSSPrimitiveValue> parsedValue2;
+ if (num == 2) {
+ value = m_valueList->next();
+ validPrimitive = validUnit(value, FLength, m_strict);
+ if (!validPrimitive)
+ return false;
+ parsedValue2 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
+ } else
+ parsedValue2 = parsedValue1;
+
+ RefPtr<Pair> pair = Pair::create(parsedValue1.release(), parsedValue2.release());
+ RefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(pair.release());
+ addProperty(propId, val.release(), important);
+ return true;
+ }
+ case CSSPropertyBorderRadius:
+ case CSSPropertyWebkitBorderRadius:
+ return parseBorderRadius(propId, important);
+ case CSSPropertyOutlineOffset:
+ validPrimitive = validUnit(value, FLength, m_strict);
+ break;
+ case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
+ case CSSPropertyWebkitBoxShadow:
+ if (id == CSSValueNone)
+ validPrimitive = true;
+ else
+ return parseShadow(propId, important);
+ break;
+ case CSSPropertyWebkitBoxReflect:
+ if (id == CSSValueNone)
+ validPrimitive = true;
+ else
+ return parseReflect(propId, important);
+ break;
+ case CSSPropertyOpacity:
+ validPrimitive = validUnit(value, FNumber, m_strict);
+ break;
+ case CSSPropertyWebkitBoxAlign:
+ if (id == CSSValueStretch || id == CSSValueStart || id == CSSValueEnd ||
+ id == CSSValueCenter || id == CSSValueBaseline)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitBoxDirection:
+ if (id == CSSValueNormal || id == CSSValueReverse)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitBoxLines:
+ if (id == CSSValueSingle || id == CSSValueMultiple)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitBoxOrient:
+ if (id == CSSValueHorizontal || id == CSSValueVertical ||
+ id == CSSValueInlineAxis || id == CSSValueBlockAxis)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitBoxPack:
+ if (id == CSSValueStart || id == CSSValueEnd ||
+ id == CSSValueCenter || id == CSSValueJustify)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitBoxFlex:
+ validPrimitive = validUnit(value, FNumber, m_strict);
+ break;
+ case CSSPropertyWebkitBoxFlexGroup:
+ case CSSPropertyWebkitBoxOrdinalGroup:
+ validPrimitive = validUnit(value, FInteger | FNonNeg, true);
+ break;
+ case CSSPropertyWebkitBoxSizing:
+ validPrimitive = id == CSSValueBorderBox || id == CSSValueContentBox;
+ break;
+ case CSSPropertyWebkitColorCorrection:
+ validPrimitive = id == CSSValueSrgb || id == CSSValueDefault;
+ break;
+ case CSSPropertyWebkitMarquee: {
+ const int properties[5] = { CSSPropertyWebkitMarqueeDirection, CSSPropertyWebkitMarqueeIncrement,
+ CSSPropertyWebkitMarqueeRepetition,
+ CSSPropertyWebkitMarqueeStyle, CSSPropertyWebkitMarqueeSpeed };
+ return parseShorthand(propId, properties, 5, important);
+ }
+ case CSSPropertyWebkitMarqueeDirection:
+ if (id == CSSValueForwards || id == CSSValueBackwards || id == CSSValueAhead ||
+ id == CSSValueReverse || id == CSSValueLeft || id == CSSValueRight || id == CSSValueDown ||
+ id == CSSValueUp || id == CSSValueAuto)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitMarqueeIncrement:
+ if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
+ validPrimitive = true;
+ else
+ validPrimitive = validUnit(value, FLength | FPercent, m_strict);
+ break;
+ case CSSPropertyWebkitMarqueeStyle:
+ if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitMarqueeRepetition:
+ if (id == CSSValueInfinite)
+ validPrimitive = true;
+ else
+ validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict);
+ break;
+ case CSSPropertyWebkitMarqueeSpeed:
+ if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
+ validPrimitive = true;
+ else
+ validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict);
+ break;
+#if ENABLE(WCSS)
+ case CSSPropertyWapMarqueeDir:
+ if (id == CSSValueLtr || id == CSSValueRtl)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWapMarqueeStyle:
+ if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWapMarqueeLoop:
+ if (id == CSSValueInfinite)
+ validPrimitive = true;
+ else
+ validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict);
+ break;
+ case CSSPropertyWapMarqueeSpeed:
+ if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
+ validPrimitive = true;
+ else
+ validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict);
+ break;
+#endif
+ case CSSPropertyWebkitUserDrag: // auto | none | element
+ if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueElement)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitUserModify: // read-only | read-write
+ if (id == CSSValueReadOnly || id == CSSValueReadWrite || id == CSSValueReadWritePlaintextOnly)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitUserSelect: // auto | none | text
+ if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueText)
+ validPrimitive = true;
+ break;
+ case CSSPropertyTextOverflow: // clip | ellipsis
+ if (id == CSSValueClip || id == CSSValueEllipsis)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitTransform:
+ if (id == CSSValueNone)
+ validPrimitive = true;
+ else {
+ PassRefPtr<CSSValue> val = parseTransform();
+ if (val) {
+ addProperty(propId, val, important);
+ return true;
+ }
+ return false;
+ }
+ break;
+ case CSSPropertyWebkitTransformOrigin:
+ case CSSPropertyWebkitTransformOriginX:
+ case CSSPropertyWebkitTransformOriginY:
+ case CSSPropertyWebkitTransformOriginZ: {
+ RefPtr<CSSValue> val1;
+ RefPtr<CSSValue> val2;
+ RefPtr<CSSValue> val3;
+ int propId1, propId2, propId3;
+ if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
+ addProperty(propId1, val1.release(), important);
+ if (val2)
+ addProperty(propId2, val2.release(), important);
+ if (val3)
+ addProperty(propId3, val3.release(), important);
+ return true;
+ }
+ return false;
+ }
+ case CSSPropertyWebkitTransformStyle:
+ if (value->id == CSSValueFlat || value->id == CSSValuePreserve3d)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitBackfaceVisibility:
+ if (value->id == CSSValueVisible || value->id == CSSValueHidden)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitPerspective:
+ if (id == CSSValueNone)
+ validPrimitive = true;
+ else {
+ // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
+ if (validUnit(value, FNumber | FLength | FNonNeg, m_strict)) {
+ RefPtr<CSSValue> val = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
+ if (val) {
+ addProperty(propId, val.release(), important);
+ return true;
+ }
+ return false;
+ }
+ }
+ break;
+ case CSSPropertyWebkitPerspectiveOrigin:
+ case CSSPropertyWebkitPerspectiveOriginX:
+ case CSSPropertyWebkitPerspectiveOriginY: {
+ RefPtr<CSSValue> val1;
+ RefPtr<CSSValue> val2;
+ int propId1, propId2;
+ if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
+ addProperty(propId1, val1.release(), important);
+ if (val2)
+ addProperty(propId2, val2.release(), important);
+ return true;
+ }
+ return false;
+ }
+ case CSSPropertyWebkitAnimationDelay:
+ case CSSPropertyWebkitAnimationDirection:
+ case CSSPropertyWebkitAnimationDuration:
+ case CSSPropertyWebkitAnimationFillMode:
+ case CSSPropertyWebkitAnimationName:
+ case CSSPropertyWebkitAnimationPlayState:
+ case CSSPropertyWebkitAnimationIterationCount:
+ case CSSPropertyWebkitAnimationTimingFunction:
+ case CSSPropertyWebkitTransitionDelay:
+ case CSSPropertyWebkitTransitionDuration:
+ case CSSPropertyWebkitTransitionTimingFunction:
+ case CSSPropertyWebkitTransitionProperty: {
+ RefPtr<CSSValue> val;
+ if (parseAnimationProperty(propId, val)) {
+ addProperty(propId, val.release(), important);
+ return true;
+ }
+ return false;
+ }
+ case CSSPropertyWebkitMarginCollapse: {
+ const int properties[2] = { CSSPropertyWebkitMarginTopCollapse,
+ CSSPropertyWebkitMarginBottomCollapse };
+ if (num == 1) {
+ ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
+ if (!parseValue(properties[0], important))
+ return false;
+ CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value();
+ addProperty(properties[1], value, important);
+ return true;
+ }
+ else if (num == 2) {
+ ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
+ if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
+ return false;
+ return true;
+ }
+ return false;
+ }
+ case CSSPropertyWebkitMarginTopCollapse:
+ case CSSPropertyWebkitMarginBottomCollapse:
+ if (id == CSSValueCollapse || id == CSSValueSeparate || id == CSSValueDiscard)
+ validPrimitive = true;
+ break;
+ case CSSPropertyTextLineThroughMode:
+ case CSSPropertyTextOverlineMode:
+ case CSSPropertyTextUnderlineMode:
+ if (id == CSSValueContinuous || id == CSSValueSkipWhiteSpace)
+ validPrimitive = true;
+ break;
+ case CSSPropertyTextLineThroughStyle:
+ case CSSPropertyTextOverlineStyle:
+ case CSSPropertyTextUnderlineStyle:
+ if (id == CSSValueNone || id == CSSValueSolid || id == CSSValueDouble ||
+ id == CSSValueDashed || id == CSSValueDotDash || id == CSSValueDotDotDash ||
+ id == CSSValueWave)
+ validPrimitive = true;
+ break;
+ case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
+ if (id == CSSValueAuto || id == CSSValueOptimizespeed || id == CSSValueOptimizelegibility
+ || id == CSSValueGeometricprecision)
+ validPrimitive = true;
+ break;
+ case CSSPropertyTextLineThroughWidth:
+ case CSSPropertyTextOverlineWidth:
+ case CSSPropertyTextUnderlineWidth:
+ if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
+ id == CSSValueMedium || id == CSSValueThick)
+ validPrimitive = true;
+ else
+ validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent, m_strict);
+ break;
+ case CSSPropertyResize: // none | both | horizontal | vertical | auto
+ if (id == CSSValueNone || id == CSSValueBoth || id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitColumnCount:
+ if (id == CSSValueAuto)
+ validPrimitive = true;
+ else
+ validPrimitive = !id && validUnit(value, FInteger | FNonNeg, false);
+ break;
+ case CSSPropertyWebkitColumnGap: // normal | <length>
+ if (id == CSSValueNormal)
+ validPrimitive = true;
+ else
+ validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
+ break;
+ case CSSPropertyWebkitColumnSpan: // all | 1
+ if (id == CSSValueAll)
+ validPrimitive = true;
+ else
+ validPrimitive = validUnit(value, FNumber | FNonNeg, m_strict) && value->fValue == 1;
+ break;
+ case CSSPropertyWebkitColumnWidth: // auto | <length>
+ if (id == CSSValueAuto)
+ validPrimitive = true;
+ else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property.
+ validPrimitive = validUnit(value, FLength, true);
+ break;
+ case CSSPropertyPointerEvents:
+ // none | visiblePainted | visibleFill | visibleStroke | visible |
+ // painted | fill | stroke | auto | all | inherit
+ if (id == CSSValueVisible || id == CSSValueNone || id == CSSValueAll || id == CSSValueAuto ||
+ (id >= CSSValueVisiblepainted && id <= CSSValueStroke))
+ validPrimitive = true;
+ break;
+
+ // End of CSS3 properties
+
+ // Apple specific properties. These will never be standardized and are purely to
+ // support custom WebKit-based Apple applications.
+ case CSSPropertyWebkitLineClamp:
+ // When specifying number of lines, don't allow 0 as a valid value
+ // When specifying either type of unit, require non-negative integers
+ validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, false));
+ break;
+ case CSSPropertyWebkitTextSizeAdjust:
+ if (id == CSSValueAuto || id == CSSValueNone)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitRtlOrdering:
+ if (id == CSSValueLogical || id == CSSValueVisual)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyWebkitFontSizeDelta: // <length>
+ validPrimitive = validUnit(value, FLength, m_strict);
+ break;
+
+ case CSSPropertyWebkitNbspMode: // normal | space
+ if (id == CSSValueNormal || id == CSSValueSpace)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyWebkitLineBreak: // normal | after-white-space
+ if (id == CSSValueNormal || id == CSSValueAfterWhiteSpace)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyWebkitMatchNearestMailBlockquoteColor: // normal | match
+ if (id == CSSValueNormal || id == CSSValueMatch)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyWebkitHighlight:
+ if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyWebkitHyphens:
+ if (id == CSSValueNone || id == CSSValueManual || id == CSSValueAuto)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyWebkitHyphenateCharacter:
+ if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyWebkitBorderFit:
+ if (id == CSSValueBorder || id == CSSValueLines)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyWebkitTextSecurity:
+ // disc | circle | square | none | inherit
+ if (id == CSSValueDisc || id == CSSValueCircle || id == CSSValueSquare|| id == CSSValueNone)
+ validPrimitive = true;
+ break;
+
+ case CSSPropertyWebkitFontSmoothing:
+ if (id == CSSValueAuto || id == CSSValueNone
+ || id == CSSValueAntialiased || id == CSSValueSubpixelAntialiased)
+ validPrimitive = true;
+ break;
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region>
+ if (value->unit == CSSParserValue::Function || id == CSSValueNone)
+ return parseDashboardRegions(propId, important);
+ break;
+#endif
+ // End Apple-specific properties
+
+ /* shorthand properties */
+ case CSSPropertyBackground: {
+ // Position must come before color in this array because a plain old "0" is a legal color
+ // in quirks mode but it's usually the X coordinate of a position.
+ // FIXME: Add CSSPropertyBackgroundSize to the shorthand.
+ const int properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
+ CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
+ CSSPropertyBackgroundColor };
+ return parseFillShorthand(propId, properties, 6, important);
+ }
+ case CSSPropertyWebkitMask: {
+ const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
+ CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition,
+ CSSPropertyWebkitMaskOrigin };
+ return parseFillShorthand(propId, properties, 5, important);
+ }
+ case CSSPropertyBorder:
+ // [ 'border-width' || 'border-style' || <color> ] | inherit
+ {
+ const int properties[3] = { CSSPropertyBorderWidth, CSSPropertyBorderStyle,
+ CSSPropertyBorderColor };
+ return parseShorthand(propId, properties, 3, important);
+ }
+ case CSSPropertyBorderTop:
+ // [ 'border-top-width' || 'border-style' || <color> ] | inherit
+ {
+ const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle,
+ CSSPropertyBorderTopColor};
+ return parseShorthand(propId, properties, 3, important);
+ }
+ case CSSPropertyBorderRight:
+ // [ 'border-right-width' || 'border-style' || <color> ] | inherit
+ {
+ const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle,
+ CSSPropertyBorderRightColor };
+ return parseShorthand(propId, properties, 3, important);
+ }
+ case CSSPropertyBorderBottom:
+ // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
+ {
+ const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle,
+ CSSPropertyBorderBottomColor };
+ return parseShorthand(propId, properties, 3, important);
+ }
+ case CSSPropertyBorderLeft:
+ // [ 'border-left-width' || 'border-style' || <color> ] | inherit
+ {
+ const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle,
+ CSSPropertyBorderLeftColor };
+ return parseShorthand(propId, properties, 3, important);
+ }
+ case CSSPropertyWebkitBorderStart:
+ // [ '-webkit-border-start-width' || 'border-style' || <color> ] | inherit
+ {
+ const int properties[3] = { CSSPropertyWebkitBorderStartWidth, CSSPropertyWebkitBorderStartStyle,
+ CSSPropertyWebkitBorderStartColor };
+ return parseShorthand(propId, properties, 3, important);
+ }
+ case CSSPropertyWebkitBorderEnd:
+ // [ '-webkit-border-end-width' || 'border-style' || <color> ] | inherit
+ {
+ const int properties[3] = { CSSPropertyWebkitBorderEndWidth, CSSPropertyWebkitBorderEndStyle,
+ CSSPropertyWebkitBorderEndColor };
+ return parseShorthand(propId, properties, 3, important);
+ }
+ case CSSPropertyOutline:
+ // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
+ {
+ const int properties[3] = { CSSPropertyOutlineWidth, CSSPropertyOutlineStyle,
+ CSSPropertyOutlineColor };
+ return parseShorthand(propId, properties, 3, important);
+ }
+ case CSSPropertyBorderColor:
+ // <color>{1,4} | inherit
+ {
+ const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor,
+ CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor };
+ return parse4Values(propId, properties, important);
+ }
+ case CSSPropertyBorderWidth:
+ // <border-width>{1,4} | inherit
+ {
+ const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth,
+ CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth };
+ return parse4Values(propId, properties, important);
+ }
+ case CSSPropertyBorderStyle:
+ // <border-style>{1,4} | inherit
+ {
+ const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle,
+ CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle };
+ return parse4Values(propId, properties, important);
+ }
+ case CSSPropertyMargin:
+ // <margin-width>{1,4} | inherit
+ {
+ const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight,
+ CSSPropertyMarginBottom, CSSPropertyMarginLeft };
+ return parse4Values(propId, properties, important);
+ }
+ case CSSPropertyPadding:
+ // <padding-width>{1,4} | inherit
+ {
+ const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight,
+ CSSPropertyPaddingBottom, CSSPropertyPaddingLeft };
+ return parse4Values(propId, properties, important);
+ }
+ case CSSPropertyFont:
+ // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
+ // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
+ if (id >= CSSValueCaption && id <= CSSValueStatusBar)
+ validPrimitive = true;
+ else
+ return parseFont(important);
+ break;
+ case CSSPropertyListStyle:
+ {
+ const int properties[3] = { CSSPropertyListStyleType, CSSPropertyListStylePosition,
+ CSSPropertyListStyleImage };
+ return parseShorthand(propId, properties, 3, important);
+ }
+ case CSSPropertyWebkitColumns: {
+ const int properties[2] = { CSSPropertyWebkitColumnWidth, CSSPropertyWebkitColumnCount };
+ return parseShorthand(propId, properties, 2, important);
+ }
+ case CSSPropertyWebkitColumnRule: {
+ const int properties[3] = { CSSPropertyWebkitColumnRuleWidth, CSSPropertyWebkitColumnRuleStyle,
+ CSSPropertyWebkitColumnRuleColor };
+ return parseShorthand(propId, properties, 3, important);
+ }
+ case CSSPropertyWebkitTextStroke: {
+ const int properties[2] = { CSSPropertyWebkitTextStrokeWidth, CSSPropertyWebkitTextStrokeColor };
+ return parseShorthand(propId, properties, 2, important);
+ }
+ case CSSPropertyWebkitAnimation:
+ return parseAnimationShorthand(important);
+ case CSSPropertyWebkitTransition:
+ return parseTransitionShorthand(important);
+ case CSSPropertyInvalid:
+ return false;
+ case CSSPropertyPage:
+ return parsePage(propId, important);
+ case CSSPropertyFontStretch:
+ case CSSPropertyTextLineThrough:
+ case CSSPropertyTextOverline:
+ case CSSPropertyTextUnderline:
+ case CSSPropertyWebkitVariableDeclarationBlock:
+ return false;
+#if 0 // :HACK:
+ case CSSPropertyWebkitHapticTapType:
+ if (id == CSSValueButton || id == CSSValueLatchedButtonDown || id == CSSValueLatchedButtonUp || id == CSSValueLatchedButtonStuck
+ || id == CSSValueLink || id == CSSValueCheckedCheckbox || id == CSSValueUncheckedCheckbox)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitHapticTapStrength:
+ if (id == CSSValueNone || id == CSSValueWeak || id == CSSValueMedium || id == CSSValueStrong)
+ validPrimitive = true;
+ break;
+ case CSSPropertyWebkitHapticTap: {
+ const int properties[2] = { CSSPropertyWebkitHapticTapType, CSSPropertyWebkitHapticTapStrength};
+ return parseShorthand(propId, properties, 2, important);
+ }
+#endif
+#if ENABLE(WCSS)
+ case CSSPropertyWapInputFormat:
+ validPrimitive = true;
+ break;
+ case CSSPropertyWapInputRequired:
+ parsedValue = parseWCSSInputProperty();
+ break;
+#endif
+
+#if ENABLE(SVG)
+ default:
+ return parseSVGValue(propId, important);
+#endif
+ }
+
+ if (validPrimitive) {
+ if (id != 0)
+ parsedValue = CSSPrimitiveValue::createIdentifier(id);
+ else if (value->unit == CSSPrimitiveValue::CSS_STRING)
+ parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
+ else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
+ parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
+ else if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS)
+ parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
+ else if (value->unit >= CSSParserValue::Q_EMS)
+ parsedValue = CSSQuirkPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_EMS);
+ m_valueList->next();
+ }
+ if (parsedValue) {
+ if (!m_valueList->current() || inShorthand()) {
+ addProperty(propId, parsedValue.release(), important);
+ return true;
+ }
+ }
+ return false;
+}
+
+#if ENABLE(WCSS)
+PassRefPtr<CSSValue> CSSParser::parseWCSSInputProperty()
+{
+ RefPtr<CSSValue> parsedValue = 0;
+ CSSParserValue* value = m_valueList->current();
+ String inputProperty;
+ if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT)
+ inputProperty = String(value->string);
+
+ if (!inputProperty.isEmpty())
+ parsedValue = CSSPrimitiveValue::create(inputProperty, CSSPrimitiveValue::CSS_STRING);
+
+ while (m_valueList->next()) {
+ // pass all other values, if any. If we don't do this,
+ // the parser will think that it's not done and won't process this property
+ }
+
+ return parsedValue;
+}
+#endif
+
+void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
+{
+ if (lval) {
+ if (lval->isValueList())
+ static_cast<CSSValueList*>(lval.get())->append(rval);
+ else {
+ PassRefPtr<CSSValue> oldlVal(lval.release());
+ PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
+ list->append(oldlVal);
+ list->append(rval);
+ lval = list;
+ }
+ }
+ else
+ lval = rval;
+}
+
+static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue)
+{
+ if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox || parserValue->id == CSSValueWebkitText) {
+ cssValue = CSSPrimitiveValue::createIdentifier(parserValue->id);
+ return true;
+ }
+ return false;
+}
+
+const int cMaxFillProperties = 9;
+
+bool CSSParser::parseFillShorthand(int propId, const int* properties, int numProperties, bool important)
+{
+ ASSERT(numProperties <= cMaxFillProperties);
+ if (numProperties > cMaxFillProperties)
+ return false;
+
+ ShorthandScope scope(this, propId);
+
+ bool parsedProperty[cMaxFillProperties] = { false };
+ RefPtr<CSSValue> values[cMaxFillProperties];
+ RefPtr<CSSValue> clipValue;
+ RefPtr<CSSValue> positionYValue;
+ RefPtr<CSSValue> repeatYValue;
+ int i;
+
+ while (m_valueList->current()) {
+ CSSParserValue* val = m_valueList->current();
+ if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
+ // We hit the end. Fill in all remaining values with the initial value.
+ m_valueList->next();
+ for (i = 0; i < numProperties; ++i) {
+ if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
+ // Color is not allowed except as the last item in a list for backgrounds.
+ // Reject the entire property.
+ return false;
+
+ if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
+ addFillValue(values[i], CSSInitialValue::createImplicit());
+ if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
+ addFillValue(positionYValue, CSSInitialValue::createImplicit());
+ if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
+ addFillValue(repeatYValue, CSSInitialValue::createImplicit());
+ if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
+ // If background-origin wasn't present, then reset background-clip also.
+ addFillValue(clipValue, CSSInitialValue::createImplicit());
+ }
+ }
+ parsedProperty[i] = false;
+ }
+ if (!m_valueList->current())
+ break;
+ }
+
+ bool found = false;
+ for (i = 0; !found && i < numProperties; ++i) {
+ if (!parsedProperty[i]) {
+ RefPtr<CSSValue> val1;
+ RefPtr<CSSValue> val2;
+ int propId1, propId2;
+ CSSParserValue* parserValue = m_valueList->current();
+ if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
+ parsedProperty[i] = found = true;
+ addFillValue(values[i], val1.release());
+ if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
+ addFillValue(positionYValue, val2.release());
+ if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
+ addFillValue(repeatYValue, val2.release());
+ if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
+ // Reparse the value as a clip, and see if we succeed.
+ if (parseBackgroundClip(parserValue, val1))
+ addFillValue(clipValue, val1.release()); // The property parsed successfully.
+ else
+ addFillValue(clipValue, CSSInitialValue::createImplicit()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
+ }
+ }
+ }
+ }
+
+ // if we didn't find at least one match, this is an
+ // invalid shorthand and we have to ignore it
+ if (!found)
+ return false;
+ }
+
+ // Fill in any remaining properties with the initial value.
+ for (i = 0; i < numProperties; ++i) {
+ if (!parsedProperty[i]) {
+ addFillValue(values[i], CSSInitialValue::createImplicit());
+ if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
+ addFillValue(positionYValue, CSSInitialValue::createImplicit());
+ if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
+ addFillValue(repeatYValue, CSSInitialValue::createImplicit());
+ if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
+ // If background-origin wasn't present, then reset background-clip also.
+ addFillValue(clipValue, CSSInitialValue::createImplicit());
+ }
+ }
+ }
+
+ // Now add all of the properties we found.
+ for (i = 0; i < numProperties; i++) {
+ if (properties[i] == CSSPropertyBackgroundPosition) {
+ addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
+ // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
+ addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
+ } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
+ addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
+ // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
+ addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
+ } else if (properties[i] == CSSPropertyBackgroundRepeat) {
+ addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
+ // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
+ addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
+ } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
+ addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
+ // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
+ addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
+ } else
+ addProperty(properties[i], values[i].release(), important);
+
+ // Add in clip values when we hit the corresponding origin property.
+ if (properties[i] == CSSPropertyBackgroundOrigin)
+ addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
+ else if (properties[i] == CSSPropertyWebkitMaskOrigin)
+ addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
+ }
+
+ return true;
+}
+
+void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
+{
+ if (lval) {
+ if (lval->isValueList())
+ static_cast<CSSValueList*>(lval.get())->append(rval);
+ else {
+ PassRefPtr<CSSValue> oldVal(lval.release());
+ PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
+ list->append(oldVal);
+ list->append(rval);
+ lval = list;
+ }
+ }
+ else
+ lval = rval;
+}
+
+bool CSSParser::parseAnimationShorthand(bool important)
+{
+ const int properties[] = { CSSPropertyWebkitAnimationName,
+ CSSPropertyWebkitAnimationDuration,
+ CSSPropertyWebkitAnimationTimingFunction,
+ CSSPropertyWebkitAnimationDelay,
+ CSSPropertyWebkitAnimationIterationCount,
+ CSSPropertyWebkitAnimationDirection,
+ CSSPropertyWebkitAnimationFillMode };
+ const int numProperties = sizeof(properties) / sizeof(properties[0]);
+
+ ShorthandScope scope(this, CSSPropertyWebkitAnimation);
+
+ bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
+ RefPtr<CSSValue> values[numProperties];
+
+ int i;
+ while (m_valueList->current()) {
+ CSSParserValue* val = m_valueList->current();
+ if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
+ // We hit the end. Fill in all remaining values with the initial value.
+ m_valueList->next();
+ for (i = 0; i < numProperties; ++i) {
+ if (!parsedProperty[i])
+ addAnimationValue(values[i], CSSInitialValue::createImplicit());
+ parsedProperty[i] = false;
+ }
+ if (!m_valueList->current())
+ break;
+ }
+
+ bool found = false;
+ for (i = 0; !found && i < numProperties; ++i) {
+ if (!parsedProperty[i]) {
+ RefPtr<CSSValue> val;
+ if (parseAnimationProperty(properties[i], val)) {
+ parsedProperty[i] = found = true;
+ addAnimationValue(values[i], val.release());
+ }
+ }
+ }
+
+ // if we didn't find at least one match, this is an
+ // invalid shorthand and we have to ignore it
+ if (!found)
+ return false;
+ }
+
+ // Fill in any remaining properties with the initial value.
+ for (i = 0; i < numProperties; ++i) {
+ if (!parsedProperty[i])
+ addAnimationValue(values[i], CSSInitialValue::createImplicit());
+ }
+
+ // Now add all of the properties we found.
+ for (i = 0; i < numProperties; i++)
+ addProperty(properties[i], values[i].release(), important);
+
+ return true;
+}
+
+bool CSSParser::parseTransitionShorthand(bool important)
+{
+ const int properties[] = { CSSPropertyWebkitTransitionProperty,
+ CSSPropertyWebkitTransitionDuration,
+ CSSPropertyWebkitTransitionTimingFunction,
+ CSSPropertyWebkitTransitionDelay };
+ const int numProperties = sizeof(properties) / sizeof(properties[0]);
+
+ ShorthandScope scope(this, CSSPropertyWebkitTransition);
+
+ bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
+ RefPtr<CSSValue> values[numProperties];
+
+ int i;
+ while (m_valueList->current()) {
+ CSSParserValue* val = m_valueList->current();
+ if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
+ // We hit the end. Fill in all remaining values with the initial value.
+ m_valueList->next();
+ for (i = 0; i < numProperties; ++i) {
+ if (!parsedProperty[i])
+ addAnimationValue(values[i], CSSInitialValue::createImplicit());
+ parsedProperty[i] = false;
+ }
+ if (!m_valueList->current())
+ break;
+ }
+
+ bool found = false;
+ for (i = 0; !found && i < numProperties; ++i) {
+ if (!parsedProperty[i]) {
+ RefPtr<CSSValue> val;
+ if (parseAnimationProperty(properties[i], val)) {
+ parsedProperty[i] = found = true;
+ addAnimationValue(values[i], val.release());
+ }
+ }
+ }
+
+ // if we didn't find at least one match, this is an
+ // invalid shorthand and we have to ignore it
+ if (!found)
+ return false;
+ }
+
+ // Fill in any remaining properties with the initial value.
+ for (i = 0; i < numProperties; ++i) {
+ if (!parsedProperty[i])
+ addAnimationValue(values[i], CSSInitialValue::createImplicit());
+ }
+
+ // Now add all of the properties we found.
+ for (i = 0; i < numProperties; i++)
+ addProperty(properties[i], values[i].release(), important);
+
+ return true;
+}
+
+bool CSSParser::parseShorthand(int propId, const int *properties, int numProperties, bool important)
+{
+ // We try to match as many properties as possible
+ // We set up an array of booleans to mark which property has been found,
+ // and we try to search for properties until it makes no longer any sense.
+ ShorthandScope scope(this, propId);
+
+ bool found = false;
+ bool fnd[6]; // Trust me ;)
+ for (int i = 0; i < numProperties; i++)
+ fnd[i] = false;
+
+ while (m_valueList->current()) {
+ found = false;
+ for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
+ if (!fnd[propIndex]) {
+ if (parseValue(properties[propIndex], important))
+ fnd[propIndex] = found = true;
+ }
+ }
+
+ // if we didn't find at least one match, this is an
+ // invalid shorthand and we have to ignore it
+ if (!found)
+ return false;
+ }
+
+ // Fill in any remaining properties with the initial value.
+ m_implicitShorthand = true;
+ for (int i = 0; i < numProperties; ++i) {
+ if (!fnd[i])
+ addProperty(properties[i], CSSInitialValue::createImplicit(), important);
+ }
+ m_implicitShorthand = false;
+
+ return true;
+}
+
+bool CSSParser::parse4Values(int propId, const int *properties, bool important)
+{
+ /* From the CSS 2 specs, 8.3
+ * If there is only one value, it applies to all sides. If there are two values, the top and
+ * bottom margins are set to the first value and the right and left margins are set to the second.
+ * If there are three values, the top is set to the first value, the left and right are set to the
+ * second, and the bottom is set to the third. If there are four values, they apply to the top,
+ * right, bottom, and left, respectively.
+ */
+
+ int num = inShorthand() ? 1 : m_valueList->size();
+
+ ShorthandScope scope(this, propId);
+
+ // the order is top, right, bottom, left
+ switch (num) {
+ case 1: {
+ if (!parseValue(properties[0], important))
+ return false;
+ CSSValue *value = m_parsedProperties[m_numParsedProperties-1]->value();
+ m_implicitShorthand = true;
+ addProperty(properties[1], value, important);
+ addProperty(properties[2], value, important);
+ addProperty(properties[3], value, important);
+ m_implicitShorthand = false;
+ break;
+ }
+ case 2: {
+ if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
+ return false;
+ CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value();
+ m_implicitShorthand = true;
+ addProperty(properties[2], value, important);
+ value = m_parsedProperties[m_numParsedProperties-2]->value();
+ addProperty(properties[3], value, important);
+ m_implicitShorthand = false;
+ break;
+ }
+ case 3: {
+ if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
+ return false;
+ CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value();
+ m_implicitShorthand = true;
+ addProperty(properties[3], value, important);
+ m_implicitShorthand = false;
+ break;
+ }
+ case 4: {
+ if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
+ !parseValue(properties[2], important) || !parseValue(properties[3], important))
+ return false;
+ break;
+ }
+ default: {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// auto | <identifier>
+bool CSSParser::parsePage(int propId, bool important)
+{
+ ASSERT(propId == CSSPropertyPage);
+
+ if (m_valueList->size() != 1)
+ return false;
+
+ CSSParserValue* value = m_valueList->current();
+ if (!value)
+ return false;
+
+ if (value->id == CSSValueAuto) {
+ addProperty(propId, CSSPrimitiveValue::createIdentifier(value->id), important);
+ return true;
+ } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
+ addProperty(propId, CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_STRING), important);
+ return true;
+ }
+ return false;
+}
+
+// <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
+bool CSSParser::parseSize(int propId, bool important)
+{
+ ASSERT(propId == CSSPropertySize);
+
+ if (m_valueList->size() > 2)
+ return false;
+
+ CSSParserValue* value = m_valueList->current();
+ if (!value)
+ return false;
+
+ RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
+
+ // First parameter.
+ SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
+ if (paramType == None)
+ return false;
+
+ // Second parameter, if any.
+ value = m_valueList->next();
+ if (value) {
+ paramType = parseSizeParameter(parsedValues.get(), value, paramType);
+ if (paramType == None)
+ return false;
+ }
+
+ addProperty(propId, parsedValues.release(), important);
+ return true;
+}
+
+CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
+{
+ switch (value->id) {
+ case CSSValueAuto:
+ if (prevParamType == None) {
+ parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id));
+ return Auto;
+ }
+ return None;
+ case CSSValueLandscape:
+ case CSSValuePortrait:
+ if (prevParamType == None || prevParamType == PageSize) {
+ parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id));
+ return Orientation;
+ }
+ return None;
+ case CSSValueA3:
+ case CSSValueA4:
+ case CSSValueA5:
+ case CSSValueB4:
+ case CSSValueB5:
+ case CSSValueLedger:
+ case CSSValueLegal:
+ case CSSValueLetter:
+ if (prevParamType == None || prevParamType == Orientation) {
+ // Normalize to Page Size then Orientation order by prepending.
+ // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (CSSStyleSelector::applyPageSizeProperty).
+ parsedValues->prepend(CSSPrimitiveValue::createIdentifier(value->id));
+ return PageSize;
+ }
+ return None;
+ case 0:
+ if (validUnit(value, FLength | FNonNeg, m_strict) && (prevParamType == None || prevParamType == Length)) {
+ parsedValues->append(CSSPrimitiveValue::create(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
+ return Length;
+ }
+ return None;
+ default:
+ return None;
+ }
+}
+
+// [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
+// in CSS 2.1 this got somewhat reduced:
+// [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
+bool CSSParser::parseContent(int propId, bool important)
+{
+ RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
+
+ while (CSSParserValue* val = m_valueList->current()) {
+ RefPtr<CSSValue> parsedValue;
+ if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
+ // url
+ // FIXME: The completeURL call should be done when using the CSSImageValue,
+ // not when creating it.
+ parsedValue = CSSImageValue::create(m_styleSheet->completeURL(val->string));
+ } else if (val->unit == CSSParserValue::Function) {
+ // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
+ CSSParserValueList* args = val->function->args;
+ if (!args)
+ return false;
+ if (equalIgnoringCase(val->function->name, "attr(")) {
+ parsedValue = parseAttr(args);
+ if (!parsedValue)
+ return false;
+ } else if (equalIgnoringCase(val->function->name, "counter(")) {
+ parsedValue = parseCounterContent(args, false);
+ if (!parsedValue)
+ return false;
+ } else if (equalIgnoringCase(val->function->name, "counters(")) {
+ parsedValue = parseCounterContent(args, true);
+ if (!parsedValue)
+ return false;
+ } else if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) {
+ if (!parseGradient(parsedValue))
+ return false;
+ } else if (equalIgnoringCase(val->function->name, "-webkit-canvas(")) {
+ if (!parseCanvas(parsedValue))
+ return false;
+ } else
+ return false;
+ } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
+ // open-quote
+ // close-quote
+ // no-open-quote
+ // no-close-quote
+ // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
+ } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
+ parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
+ }
+ if (!parsedValue)
+ break;
+ values->append(parsedValue.release());
+ m_valueList->next();
+ }
+
+ if (values->length()) {
+ addProperty(propId, values.release(), important);
+ m_valueList->next();
+ return true;
+ }
+
+ return false;
+}
+
+PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args)
+{
+ if (args->size() != 1)
+ return 0;
+
+ CSSParserValue* a = args->current();
+
+ if (a->unit != CSSPrimitiveValue::CSS_IDENT)
+ return 0;
+
+ String attrName = a->string;
+ // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
+ // But HTML attribute names can't have those characters, and we should not
+ // even parse them inside attr().
+ if (attrName[0] == '-')
+ return 0;
+
+ if (document() && document()->isHTMLDocument())
+ attrName = attrName.lower();
+
+ return CSSPrimitiveValue::create(attrName, CSSPrimitiveValue::CSS_ATTR);
+}
+
+PassRefPtr<CSSValue> CSSParser::parseBackgroundColor()
+{
+ int id = m_valueList->current()->id;
+ if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
+ (id >= CSSValueGrey && id < CSSValueWebkitText && !m_strict))
+ return CSSPrimitiveValue::createIdentifier(id);
+ return parseColor();
+}
+
+bool CSSParser::parseFillImage(RefPtr<CSSValue>& value)
+{
+ if (m_valueList->current()->id == CSSValueNone) {
+ value = CSSImageValue::create();
+ return true;
+ }
+ if (m_valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
+ // FIXME: The completeURL call should be done when using the CSSImageValue,
+ // not when creating it.
+ if (m_styleSheet)
+ value = CSSImageValue::create(m_styleSheet->completeURL(m_valueList->current()->string));
+ return true;
+ }
+
+ if (m_valueList->current()->unit == CSSParserValue::Function) {
+ if (equalIgnoringCase(m_valueList->current()->function->name, "-webkit-gradient("))
+ return parseGradient(value);
+ if (equalIgnoringCase(m_valueList->current()->function->name, "-webkit-canvas("))
+ return parseCanvas(value);
+ }
+
+ return false;
+}
+
+PassRefPtr<CSSValue> CSSParser::parseFillPositionXY(bool& xFound, bool& yFound)
+{
+ int id = m_valueList->current()->id;
+ if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
+ int percent = 0;
+ if (id == CSSValueLeft || id == CSSValueRight) {
+ if (xFound)
+ return 0;
+ xFound = true;
+ if (id == CSSValueRight)
+ percent = 100;
+ }
+ else if (id == CSSValueTop || id == CSSValueBottom) {
+ if (yFound)
+ return 0;
+ yFound = true;
+ if (id == CSSValueBottom)
+ percent = 100;
+ }
+ else if (id == CSSValueCenter)
+ // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
+ percent = 50;
+ return CSSPrimitiveValue::create(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
+ }
+ if (validUnit(m_valueList->current(), FPercent | FLength, m_strict))
+ return CSSPrimitiveValue::create(m_valueList->current()->fValue,
+ (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit);
+
+ return 0;
+}
+
+void CSSParser::parseFillPosition(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
+{
+ CSSParserValue* value = m_valueList->current();
+
+ // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
+ bool value1IsX = false, value1IsY = false;
+ value1 = parseFillPositionXY(value1IsX, value1IsY);
+ if (!value1)
+ return;
+
+ // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
+ // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the
+ // value was explicitly specified for our property.
+ value = m_valueList->next();
+
+ // First check for the comma. If so, we are finished parsing this value or value pair.
+ if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
+ value = 0;
+
+ bool value2IsX = false, value2IsY = false;
+ if (value) {
+ value2 = parseFillPositionXY(value2IsX, value2IsY);
+ if (value2)
+ m_valueList->next();
+ else {
+ if (!inShorthand()) {
+ value1.clear();
+ return;
+ }
+ }
+ }
+
+ if (!value2)
+ // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
+ // is simply 50%. This is our default.
+ // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
+ // For left/right/center, the default of 50% in the y is still correct.
+ value2 = CSSPrimitiveValue::create(50, CSSPrimitiveValue::CSS_PERCENTAGE);
+
+ if (value1IsY || value2IsX)
+ value1.swap(value2);
+}
+
+void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
+{
+ CSSParserValue* value = m_valueList->current();
+
+ int id = m_valueList->current()->id;
+ if (id == CSSValueRepeatX) {
+ m_implicitShorthand = true;
+ value1 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat);
+ value2 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat);
+ m_valueList->next();
+ return;
+ }
+ if (id == CSSValueRepeatY) {
+ m_implicitShorthand = true;
+ value1 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat);
+ value2 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat);
+ m_valueList->next();
+ return;
+ }
+ if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
+ value1 = CSSPrimitiveValue::createIdentifier(id);
+ else {
+ value1 = 0;
+ return;
+ }
+
+ value = m_valueList->next();
+
+ // First check for the comma. If so, we are finished parsing this value or value pair.
+ if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
+ value = 0;
+
+ if (value)
+ id = m_valueList->current()->id;
+
+ if (value && (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)) {
+ value2 = CSSPrimitiveValue::createIdentifier(id);
+ m_valueList->next();
+ } else {
+ // If only one value was specified, value2 is the same as value1.
+ m_implicitShorthand = true;
+ value2 = CSSPrimitiveValue::createIdentifier(static_cast<CSSPrimitiveValue*>(value1.get())->getIdent());
+ }
+}
+
+PassRefPtr<CSSValue> CSSParser::parseFillSize(int propId, bool& allowComma)
+{
+ allowComma = true;
+ CSSParserValue* value = m_valueList->current();
+
+ if (value->id == CSSValueContain || value->id == CSSValueCover)
+ return CSSPrimitiveValue::createIdentifier(value->id);
+
+ RefPtr<CSSPrimitiveValue> parsedValue1;
+
+ if (value->id == CSSValueAuto)
+ parsedValue1 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN);
+ else {
+ if (!validUnit(value, FLength | FPercent, m_strict))
+ return 0;
+ parsedValue1 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
+ }
+
+ CSSPropertyID property = static_cast<CSSPropertyID>(propId);
+ RefPtr<CSSPrimitiveValue> parsedValue2;
+ if ((value = m_valueList->next())) {
+ if (value->id == CSSValueAuto)
+ parsedValue2 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN);
+ else if (value->unit == CSSParserValue::Operator && value->iValue == ',')
+ allowComma = false;
+ else {
+ if (!validUnit(value, FLength | FPercent, m_strict))
+ return 0;
+ parsedValue2 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
+ }
+ }
+ if (!parsedValue2) {
+ if (property == CSSPropertyWebkitBackgroundSize || property == CSSPropertyWebkitMaskSize)
+ parsedValue2 = parsedValue1;
+ else
+ parsedValue2 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN);
+ }
+
+ return CSSPrimitiveValue::create(Pair::create(parsedValue1.release(), parsedValue2.release()));
+}
+
+bool CSSParser::parseFillProperty(int propId, int& propId1, int& propId2,
+ RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
+{
+ RefPtr<CSSValueList> values;
+ RefPtr<CSSValueList> values2;
+ CSSParserValue* val;
+ RefPtr<CSSValue> value;
+ RefPtr<CSSValue> value2;
+
+ bool allowComma = false;
+
+ retValue1 = retValue2 = 0;
+ propId1 = propId;
+ propId2 = propId;
+ if (propId == CSSPropertyBackgroundPosition) {
+ propId1 = CSSPropertyBackgroundPositionX;
+ propId2 = CSSPropertyBackgroundPositionY;
+ } else if (propId == CSSPropertyWebkitMaskPosition) {
+ propId1 = CSSPropertyWebkitMaskPositionX;
+ propId2 = CSSPropertyWebkitMaskPositionY;
+ } else if (propId == CSSPropertyBackgroundRepeat) {
+ propId1 = CSSPropertyBackgroundRepeatX;
+ propId2 = CSSPropertyBackgroundRepeatY;
+ } else if (propId == CSSPropertyWebkitMaskRepeat) {
+ propId1 = CSSPropertyWebkitMaskRepeatX;
+ propId2 = CSSPropertyWebkitMaskRepeatY;
+ }
+
+ while ((val = m_valueList->current())) {
+ RefPtr<CSSValue> currValue;
+ RefPtr<CSSValue> currValue2;
+
+ if (allowComma) {
+ if (val->unit != CSSParserValue::Operator || val->iValue != ',')
+ return false;
+ m_valueList->next();
+ allowComma = false;
+ } else {
+ allowComma = true;
+ switch (propId) {
+ case CSSPropertyBackgroundColor:
+ currValue = parseBackgroundColor();
+ if (currValue)
+ m_valueList->next();
+ break;
+ case CSSPropertyBackgroundAttachment:
+ case CSSPropertyWebkitMaskAttachment:
+ if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
+ currValue = CSSPrimitiveValue::createIdentifier(val->id);
+ m_valueList->next();
+ }
+ break;
+ case CSSPropertyBackgroundImage:
+ case CSSPropertyWebkitMaskImage:
+ if (parseFillImage(currValue))
+ m_valueList->next();
+ break;
+ case CSSPropertyWebkitBackgroundClip:
+ case CSSPropertyWebkitBackgroundOrigin:
+ case CSSPropertyWebkitMaskClip:
+ case CSSPropertyWebkitMaskOrigin:
+ // The first three values here are deprecated and do not apply to the version of the property that has
+ // the -webkit- prefix removed.
+ if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
+ val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
+ ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
+ (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
+ currValue = CSSPrimitiveValue::createIdentifier(val->id);
+ m_valueList->next();
+ }
+ break;
+ case CSSPropertyBackgroundClip:
+ if (parseBackgroundClip(val, currValue))
+ m_valueList->next();
+ break;
+ case CSSPropertyBackgroundOrigin:
+ if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
+ currValue = CSSPrimitiveValue::createIdentifier(val->id);
+ m_valueList->next();
+ }
+ break;
+ case CSSPropertyBackgroundPosition:
+ case CSSPropertyWebkitMaskPosition:
+ parseFillPosition(currValue, currValue2);
+ // parseFillPosition advances the m_valueList pointer
+ break;
+ case CSSPropertyBackgroundPositionX:
+ case CSSPropertyWebkitMaskPositionX: {
+ bool xFound = false, yFound = true;
+ currValue = parseFillPositionXY(xFound, yFound);
+ if (currValue)
+ m_valueList->next();
+ break;
+ }
+ case CSSPropertyBackgroundPositionY:
+ case CSSPropertyWebkitMaskPositionY: {
+ bool xFound = true, yFound = false;
+ currValue = parseFillPositionXY(xFound, yFound);
+ if (currValue)
+ m_valueList->next();
+ break;
+ }
+ case CSSPropertyWebkitBackgroundComposite:
+ case CSSPropertyWebkitMaskComposite:
+ if ((val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) || val->id == CSSValueHighlight) {
+ currValue = CSSPrimitiveValue::createIdentifier(val->id);
+ m_valueList->next();
+ }
+ break;
+ case CSSPropertyBackgroundRepeat:
+ case CSSPropertyWebkitMaskRepeat:
+ parseFillRepeat(currValue, currValue2);
+ // parseFillRepeat advances the m_valueList pointer
+ break;
+ case CSSPropertyBackgroundSize:
+ case CSSPropertyWebkitBackgroundSize:
+ case CSSPropertyWebkitMaskSize: {
+ currValue = parseFillSize(propId, allowComma);
+ if (currValue)
+ m_valueList->next();
+ break;
+ }
+ }
+ if (!currValue)
+ return false;
+
+ if (value && !values) {
+ values = CSSValueList::createCommaSeparated();
+ values->append(value.release());
+ }
+
+ if (value2 && !values2) {
+ values2 = CSSValueList::createCommaSeparated();
+ values2->append(value2.release());
+ }
+
+ if (values)
+ values->append(currValue.release());
+ else
+ value = currValue.release();
+ if (currValue2) {
+ if (values2)
+ values2->append(currValue2.release());
+ else
+ value2 = currValue2.release();
+ }
+ }
+
+ // When parsing any fill shorthand property, we let it handle building up the lists for all
+ // properties.
+ if (inShorthand())
+ break;
+ }
+
+ if (values && values->length()) {
+ retValue1 = values.release();
+ if (values2 && values2->length())
+ retValue2 = values2.release();
+ return true;
+ }
+ if (value) {
+ retValue1 = value.release();
+ retValue2 = value2.release();
+ return true;
+ }
+ return false;
+}
+
+PassRefPtr<CSSValue> CSSParser::parseAnimationDelay()
+{
+ CSSParserValue* value = m_valueList->current();
+ if (validUnit(value, FTime, m_strict))
+ return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
+ return 0;
+}
+
+PassRefPtr<CSSValue> CSSParser::parseAnimationDirection()
+{
+ CSSParserValue* value = m_valueList->current();
+ if (value->id == CSSValueNormal || value->id == CSSValueAlternate)
+ return CSSPrimitiveValue::createIdentifier(value->id);
+ return 0;
+}
+
+PassRefPtr<CSSValue> CSSParser::parseAnimationDuration()
+{
+ CSSParserValue* value = m_valueList->current();
+ if (validUnit(value, FTime | FNonNeg, m_strict))
+ return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
+ return 0;
+}
+
+PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode()
+{
+ CSSParserValue* value = m_valueList->current();
+ if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
+ return CSSPrimitiveValue::createIdentifier(value->id);
+ return 0;
+}
+
+PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount()
+{
+ CSSParserValue* value = m_valueList->current();
+ if (value->id == CSSValueInfinite)
+ return CSSPrimitiveValue::createIdentifier(value->id);
+ if (validUnit(value, FInteger | FNonNeg, m_strict))
+ return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
+ return 0;
+}
+
+PassRefPtr<CSSValue> CSSParser::parseAnimationName()
+{
+ CSSParserValue* value = m_valueList->current();
+ if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
+ if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value->string, "none"))) {
+ return CSSPrimitiveValue::createIdentifier(CSSValueNone);
+ } else {
+ return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_STRING);
+ }
+ }
+ return 0;
+}
+
+PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState()
+{
+ CSSParserValue* value = m_valueList->current();
+ if (value->id == CSSValueRunning || value->id == CSSValuePaused)
+ return CSSPrimitiveValue::createIdentifier(value->id);
+ return 0;
+}
+
+PassRefPtr<CSSValue> CSSParser::parseAnimationProperty()
+{
+ CSSParserValue* value = m_valueList->current();
+ if (value->unit != CSSPrimitiveValue::CSS_IDENT)
+ return 0;
+ int result = cssPropertyID(value->string);
+ if (result)
+ return CSSPrimitiveValue::createIdentifier(result);
+ if (equalIgnoringCase(value->string, "all"))
+ return CSSPrimitiveValue::createIdentifier(CSSValueAll);
+ if (equalIgnoringCase(value->string, "none"))
+ return CSSPrimitiveValue::createIdentifier(CSSValueNone);
+ return 0;
+}
+
+void CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
+{
+ parseFillPosition(value1, value2);
+
+ // now get z
+ if (m_valueList->current() && validUnit(m_valueList->current(), FLength, m_strict))
+ value3 = CSSPrimitiveValue::create(m_valueList->current()->fValue,
+ (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit);
+ if (value3)
+ m_valueList->next();
+}
+
+bool CSSParser::parseTimingFunctionValue(CSSParserValueList*& args, double& result)
+{
+ CSSParserValue* v = args->current();
+ if (!validUnit(v, FNumber, m_strict))
+ return false;
+ result = v->fValue;
+ if (result < 0 || result > 1.0)
+ return false;
+ v = args->next();
+ if (!v)
+ // The last number in the function has no comma after it, so we're done.
+ return true;
+ if (v->unit != CSSParserValue::Operator && v->iValue != ',')
+ return false;
+ v = args->next();
+ return true;
+}
+
+PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction()
+{
+ CSSParserValue* value = m_valueList->current();
+ if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut || value->id == CSSValueEaseInOut)
+ return CSSPrimitiveValue::createIdentifier(value->id);
+
+ // We must be a function.
+ if (value->unit != CSSParserValue::Function)
+ return 0;
+
+ // The only timing function we accept for now is a cubic bezier function. 4 points must be specified.
+ CSSParserValueList* args = value->function->args;
+ if (!equalIgnoringCase(value->function->name, "cubic-bezier(") || !args || args->size() != 7)
+ return 0;
+
+ // There are two points specified. The values must be between 0 and 1.
+ double x1, y1, x2, y2;
+
+ if (!parseTimingFunctionValue(args, x1))
+ return 0;
+ if (!parseTimingFunctionValue(args, y1))
+ return 0;
+ if (!parseTimingFunctionValue(args, x2))
+ return 0;
+ if (!parseTimingFunctionValue(args, y2))
+ return 0;
+
+ return CSSTimingFunctionValue::create(x1, y1, x2, y2);
+}
+
+bool CSSParser::parseAnimationProperty(int propId, RefPtr<CSSValue>& result)
+{
+ RefPtr<CSSValueList> values;
+ CSSParserValue* val;
+ RefPtr<CSSValue> value;
+ bool allowComma = false;
+
+ result = 0;
+
+ while ((val = m_valueList->current())) {
+ RefPtr<CSSValue> currValue;
+ if (allowComma) {
+ if (val->unit != CSSParserValue::Operator || val->iValue != ',')
+ return false;
+ m_valueList->next();
+ allowComma = false;
+ }
+ else {
+ switch (propId) {
+ case CSSPropertyWebkitAnimationDelay:
+ case CSSPropertyWebkitTransitionDelay:
+ currValue = parseAnimationDelay();
+ if (currValue)
+ m_valueList->next();
+ break;
+ case CSSPropertyWebkitAnimationDirection:
+ currValue = parseAnimationDirection();
+ if (currValue)
+ m_valueList->next();
+ break;
+ case CSSPropertyWebkitAnimationDuration:
+ case CSSPropertyWebkitTransitionDuration:
+ currValue = parseAnimationDuration();
+ if (currValue)
+ m_valueList->next();
+ break;
+ case CSSPropertyWebkitAnimationFillMode:
+ currValue = parseAnimationFillMode();
+ if (currValue)
+ m_valueList->next();
+ break;
+ case CSSPropertyWebkitAnimationIterationCount:
+ currValue = parseAnimationIterationCount();
+ if (currValue)
+ m_valueList->next();
+ break;
+ case CSSPropertyWebkitAnimationName:
+ currValue = parseAnimationName();
+ if (currValue)
+ m_valueList->next();
+ break;
+ case CSSPropertyWebkitAnimationPlayState:
+ currValue = parseAnimationPlayState();
+ if (currValue)
+ m_valueList->next();
+ break;
+ case CSSPropertyWebkitTransitionProperty:
+ currValue = parseAnimationProperty();
+ if (currValue)
+ m_valueList->next();
+ break;
+ case CSSPropertyWebkitAnimationTimingFunction:
+ case CSSPropertyWebkitTransitionTimingFunction:
+ currValue = parseAnimationTimingFunction();
+ if (currValue)
+ m_valueList->next();
+ break;
+ }
+
+ if (!currValue)
+ return false;
+
+ if (value && !values) {
+ values = CSSValueList::createCommaSeparated();
+ values->append(value.release());
+ }
+
+ if (values)
+ values->append(currValue.release());
+ else
+ value = currValue.release();
+
+ allowComma = true;
+ }
+
+ // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
+ // properties.
+ if (inShorthand())
+ break;
+ }
+
+ if (values && values->length()) {
+ result = values.release();
+ return true;
+ }
+ if (value) {
+ result = value.release();
+ return true;
+ }
+ return false;
+}
+
+
+
+#if ENABLE(DASHBOARD_SUPPORT)
+
+#define DASHBOARD_REGION_NUM_PARAMETERS 6
+#define DASHBOARD_REGION_SHORT_NUM_PARAMETERS 2
+
+static CSSParserValue* skipCommaInDashboardRegion(CSSParserValueList *args)
+{
+ if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) ||
+ args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
+ CSSParserValue* current = args->current();
+ if (current->unit == CSSParserValue::Operator && current->iValue == ',')
+ return args->next();
+ }
+ return args->current();
+}
+
+bool CSSParser::parseDashboardRegions(int propId, bool important)
+{
+ bool valid = true;
+
+ CSSParserValue* value = m_valueList->current();
+
+ if (value->id == CSSValueNone) {
+ if (m_valueList->next())
+ return false;
+ addProperty(propId, CSSPrimitiveValue::createIdentifier(value->id), important);
+ return valid;
+ }
+
+ RefPtr<DashboardRegion> firstRegion = DashboardRegion::create();
+ DashboardRegion* region = 0;
+
+ while (value) {
+ if (region == 0) {
+ region = firstRegion.get();
+ } else {
+ RefPtr<DashboardRegion> nextRegion = DashboardRegion::create();
+ region->m_next = nextRegion;
+ region = nextRegion.get();
+ }
+
+ if (value->unit != CSSParserValue::Function) {
+ valid = false;
+ break;
+ }
+
+ // Commas count as values, so allow:
+ // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
+ // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
+ // also allow
+ // dashboard-region(label, type) or dashboard-region(label type)
+ // dashboard-region(label, type) or dashboard-region(label type)
+ CSSParserValueList* args = value->function->args;
+ if (!equalIgnoringCase(value->function->name, "dashboard-region(") || !args) {
+ valid = false;
+ break;
+ }
+
+ int numArgs = args->size();
+ if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) &&
+ (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))) {
+ valid = false;
+ break;
+ }
+
+ // First arg is a label.
+ CSSParserValue* arg = args->current();
+ if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
+ valid = false;
+ break;
+ }
+
+ region->m_label = arg->string;
+
+ // Second arg is a type.
+ arg = args->next();
+ arg = skipCommaInDashboardRegion(args);
+ if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
+ valid = false;
+ break;
+ }
+
+ if (equalIgnoringCase(arg->string, "circle"))
+ region->m_isCircle = true;
+ else if (equalIgnoringCase(arg->string, "rectangle"))
+ region->m_isRectangle = true;
+ else {
+ valid = false;
+ break;
+ }
+
+ region->m_geometryType = arg->string;
+
+ if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
+ // This originally used CSSValueInvalid by accident. It might be more logical to use something else.
+ RefPtr<CSSPrimitiveValue> amount = CSSPrimitiveValue::createIdentifier(CSSValueInvalid);
+
+ region->setTop(amount);
+ region->setRight(amount);
+ region->setBottom(amount);
+ region->setLeft(amount);
+ } else {
+ // Next four arguments must be offset numbers
+ int i;
+ for (i = 0; i < 4; i++) {
+ arg = args->next();
+ arg = skipCommaInDashboardRegion(args);
+
+ valid = arg->id == CSSValueAuto || validUnit(arg, FLength, m_strict);
+ if (!valid)
+ break;
+
+ RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ?
+ CSSPrimitiveValue::createIdentifier(CSSValueAuto) :
+ CSSPrimitiveValue::create(arg->fValue, (CSSPrimitiveValue::UnitTypes) arg->unit);
+
+ if (i == 0)
+ region->setTop(amount);
+ else if (i == 1)
+ region->setRight(amount);
+ else if (i == 2)
+ region->setBottom(amount);
+ else
+ region->setLeft(amount);
+ }
+ }
+
+ if (args->next())
+ return false;
+
+ value = m_valueList->next();
+ }
+
+ if (valid)
+ addProperty(propId, CSSPrimitiveValue::create(firstRegion.release()), important);
+
+ return valid;
+}
+
+#endif /* ENABLE(DASHBOARD_SUPPORT) */
+
+PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
+{
+ unsigned numArgs = args->size();
+ if (counters && numArgs != 3 && numArgs != 5)
+ return 0;
+ if (!counters && numArgs != 1 && numArgs != 3)
+ return 0;
+
+ CSSParserValue* i = args->current();
+ if (i->unit != CSSPrimitiveValue::CSS_IDENT)
+ return 0;
+ RefPtr<CSSPrimitiveValue> identifier = CSSPrimitiveValue::create(i->string, CSSPrimitiveValue::CSS_STRING);
+
+ RefPtr<CSSPrimitiveValue> separator;
+ if (!counters)
+ separator = CSSPrimitiveValue::create(String(), CSSPrimitiveValue::CSS_STRING);
+ else {
+ i = args->next();
+ if (i->unit != CSSParserValue::Operator || i->iValue != ',')
+ return 0;
+
+ i = args->next();
+ if (i->unit != CSSPrimitiveValue::CSS_STRING)
+ return 0;
+
+ separator = CSSPrimitiveValue::create(i->string, (CSSPrimitiveValue::UnitTypes) i->unit);
+ }
+
+ RefPtr<CSSPrimitiveValue> listStyle;
+ i = args->next();
+ if (!i) // Make the list style default decimal
+ listStyle = CSSPrimitiveValue::create(CSSValueDecimal - CSSValueDisc, CSSPrimitiveValue::CSS_NUMBER);
+ else {
+ if (i->unit != CSSParserValue::Operator || i->iValue != ',')
+ return 0;
+
+ i = args->next();
+ if (i->unit != CSSPrimitiveValue::CSS_IDENT)
+ return 0;
+
+ short ls = 0;
+ if (i->id == CSSValueNone)
+ ls = CSSValueKatakanaIroha - CSSValueDisc + 1;
+ else if (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha)
+ ls = i->id - CSSValueDisc;
+ else
+ return 0;
+
+ listStyle = CSSPrimitiveValue::create(ls, (CSSPrimitiveValue::UnitTypes) i->unit);
+ }
+
+ return CSSPrimitiveValue::create(Counter::create(identifier.release(), listStyle.release(), separator.release()));
+}
+
+bool CSSParser::parseShape(int propId, bool important)
+{
+ CSSParserValue* value = m_valueList->current();
+ CSSParserValueList* args = value->function->args;
+
+ if (!equalIgnoringCase(value->function->name, "rect(") || !args)
+ return false;
+
+ // rect(t, r, b, l) || rect(t r b l)
+ if (args->size() != 4 && args->size() != 7)
+ return false;
+ RefPtr<Rect> rect = Rect::create();
+ bool valid = true;
+ int i = 0;
+ CSSParserValue* a = args->current();
+ while (a) {
+ valid = a->id == CSSValueAuto || validUnit(a, FLength, m_strict);
+ if (!valid)
+ break;
+ RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
+ CSSPrimitiveValue::createIdentifier(CSSValueAuto) :
+ CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
+ if (i == 0)
+ rect->setTop(length);
+ else if (i == 1)
+ rect->setRight(length);
+ else if (i == 2)
+ rect->setBottom(length);
+ else
+ rect->setLeft(length);
+ a = args->next();
+ if (a && args->size() == 7) {
+ if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
+ a = args->next();
+ } else {
+ valid = false;
+ break;
+ }
+ }
+ i++;
+ }
+ if (valid) {
+ addProperty(propId, CSSPrimitiveValue::create(rect.release()), important);
+ m_valueList->next();
+ return true;
+ }
+ return false;
+}
+
+// [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
+bool CSSParser::parseFont(bool important)
+{
+ bool valid = true;
+ CSSParserValue *value = m_valueList->current();
+ RefPtr<FontValue> font = FontValue::create();
+ // optional font-style, font-variant and font-weight
+ while (value) {
+ int id = value->id;
+ if (id) {
+ if (id == CSSValueNormal) {
+ // do nothing, it's the inital value for all three
+ } else if (id == CSSValueItalic || id == CSSValueOblique) {
+ if (font->style)
+ return false;
+ font->style = CSSPrimitiveValue::createIdentifier(id);
+ } else if (id == CSSValueSmallCaps) {
+ if (font->variant)
+ return false;
+ font->variant = CSSPrimitiveValue::createIdentifier(id);
+ } else if (id >= CSSValueBold && id <= CSSValueLighter) {
+ if (font->weight)
+ return false;
+ font->weight = CSSPrimitiveValue::createIdentifier(id);
+ } else {
+ valid = false;
+ }
+ } else if (!font->weight && validUnit(value, FInteger | FNonNeg, true)) {
+ int weight = (int)value->fValue;
+ int val = 0;
+ if (weight == 100)
+ val = CSSValue100;
+ else if (weight == 200)
+ val = CSSValue200;
+ else if (weight == 300)
+ val = CSSValue300;
+ else if (weight == 400)
+ val = CSSValue400;
+ else if (weight == 500)
+ val = CSSValue500;
+ else if (weight == 600)
+ val = CSSValue600;
+ else if (weight == 700)
+ val = CSSValue700;
+ else if (weight == 800)
+ val = CSSValue800;
+ else if (weight == 900)
+ val = CSSValue900;
+
+ if (val)
+ font->weight = CSSPrimitiveValue::createIdentifier(val);
+ else
+ valid = false;
+ } else {
+ valid = false;
+ }
+ if (!valid)
+ break;
+ value = m_valueList->next();
+ }
+ if (!value)
+ return false;
+
+ // set undefined values to default
+ if (!font->style)
+ font->style = CSSPrimitiveValue::createIdentifier(CSSValueNormal);
+ if (!font->variant)
+ font->variant = CSSPrimitiveValue::createIdentifier(CSSValueNormal);
+ if (!font->weight)
+ font->weight = CSSPrimitiveValue::createIdentifier(CSSValueNormal);
+
+ // now a font size _must_ come
+ // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
+ if (value->id >= CSSValueXxSmall && value->id <= CSSValueLarger)
+ font->size = CSSPrimitiveValue::createIdentifier(value->id);
+ else if (validUnit(value, FLength | FPercent | FNonNeg, m_strict))
+ font->size = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
+ value = m_valueList->next();
+ if (!font->size || !value)
+ return false;
+
+ if (value->unit == CSSParserValue::Operator && value->iValue == '/') {
+ // line-height
+ value = m_valueList->next();
+ if (!value)
+ return false;
+ if (value->id == CSSValueNormal) {
+ // default value, nothing to do
+ } else if (validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict))
+ font->lineHeight = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
+ else
+ return false;
+ value = m_valueList->next();
+ if (!value)
+ return false;
+ }
+
+ if (!font->lineHeight)
+ font->lineHeight = CSSPrimitiveValue::createIdentifier(CSSValueNormal);
+
+ // font family must come now
+ font->family = parseFontFamily();
+
+ if (m_valueList->current() || !font->family)
+ return false;
+
+ addProperty(CSSPropertyFont, font.release(), important);
+ return true;
+}
+
+PassRefPtr<CSSValueList> CSSParser::parseFontFamily()
+{
+ RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
+ CSSParserValue* value = m_valueList->current();
+
+ FontFamilyValue* currFamily = 0;
+ while (value) {
+ CSSParserValue* nextValue = m_valueList->next();
+ bool nextValBreaksFont = !nextValue ||
+ (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
+ bool nextValIsFontName = nextValue &&
+ ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
+ (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
+
+ if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
+ if (currFamily)
+ currFamily->appendSpaceSeparated(value->string.characters, value->string.length);
+ else if (nextValBreaksFont || !nextValIsFontName)
+ list->append(CSSPrimitiveValue::createIdentifier(value->id));
+ else {
+ RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string);
+ currFamily = newFamily.get();
+ list->append(newFamily.release());
+ }
+ } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
+ // Strings never share in a family name.
+ currFamily = 0;
+ list->append(FontFamilyValue::create(value->string));
+ } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
+ if (currFamily)
+ currFamily->appendSpaceSeparated(value->string.characters, value->string.length);
+ else if (nextValBreaksFont || !nextValIsFontName)
+ list->append(FontFamilyValue::create(value->string));
+ else {
+ RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string);
+ currFamily = newFamily.get();
+ list->append(newFamily.release());
+ }
+ } else {
+ break;
+ }
+
+ if (!nextValue)
+ break;
+
+ if (nextValBreaksFont) {
+ value = m_valueList->next();
+ currFamily = 0;
+ }
+ else if (nextValIsFontName)
+ value = nextValue;
+ else
+ break;
+ }
+ if (!list->length())
+ list = 0;
+ return list.release();
+}
+
+bool CSSParser::parseFontStyle(bool important)
+{
+ RefPtr<CSSValueList> values;
+ if (m_valueList->size() > 1)
+ values = CSSValueList::createCommaSeparated();
+ CSSParserValue* val;
+ bool expectComma = false;
+ while ((val = m_valueList->current())) {
+ RefPtr<CSSPrimitiveValue> parsedValue;
+ if (!expectComma) {
+ expectComma = true;
+ if (val->id == CSSValueNormal || val->id == CSSValueItalic || val->id == CSSValueOblique)
+ parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
+ else if (val->id == CSSValueAll && !values) {
+ // 'all' is only allowed in @font-face and with no other values. Make a value list to
+ // indicate that we are in the @font-face case.
+ values = CSSValueList::createCommaSeparated();
+ parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
+ }
+ } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
+ expectComma = false;
+ m_valueList->next();
+ continue;
+ }
+
+ if (!parsedValue)
+ return false;
+
+ m_valueList->next();
+
+ if (values)
+ values->append(parsedValue.release());
+ else {
+ addProperty(CSSPropertyFontStyle, parsedValue.release(), important);
+ return true;
+ }
+ }
+
+ if (values && values->length()) {
+ m_hasFontFaceOnlyValues = true;
+ addProperty(CSSPropertyFontStyle, values.release(), important);
+ return true;
+ }
+
+ return false;
+}
+
+bool CSSParser::parseFontVariant(bool important)
+{
+ RefPtr<CSSValueList> values;
+ if (m_valueList->size() > 1)
+ values = CSSValueList::createCommaSeparated();
+ CSSParserValue* val;
+ bool expectComma = false;
+ while ((val = m_valueList->current())) {
+ RefPtr<CSSPrimitiveValue> parsedValue;
+ if (!expectComma) {
+ expectComma = true;
+ if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
+ parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
+ else if (val->id == CSSValueAll && !values) {
+ // 'all' is only allowed in @font-face and with no other values. Make a value list to
+ // indicate that we are in the @font-face case.
+ values = CSSValueList::createCommaSeparated();
+ parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
+ }
+ } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
+ expectComma = false;
+ m_valueList->next();
+ continue;
+ }
+
+ if (!parsedValue)
+ return false;
+
+ m_valueList->next();
+
+ if (values)
+ values->append(parsedValue.release());
+ else {
+ addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
+ return true;
+ }
+ }
+
+ if (values && values->length()) {
+ m_hasFontFaceOnlyValues = true;
+ addProperty(CSSPropertyFontVariant, values.release(), important);
+ return true;
+ }
+
+ return false;
+}
+
+bool CSSParser::parseFontWeight(bool important)
+{
+ RefPtr<CSSValueList> values;
+ if (m_valueList->size() > 1)
+ values = CSSValueList::createCommaSeparated();
+ CSSParserValue* val;
+ bool expectComma = false;
+ while ((val = m_valueList->current())) {
+ RefPtr<CSSPrimitiveValue> parsedValue;
+ if (!expectComma) {
+ expectComma = true;
+ if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
+ if (val->id >= CSSValueNormal && val->id <= CSSValue900)
+ parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
+ else if (val->id == CSSValueAll && !values) {
+ // 'all' is only allowed in @font-face and with no other values. Make a value list to
+ // indicate that we are in the @font-face case.
+ values = CSSValueList::createCommaSeparated();
+ parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
+ }
+ } else if (validUnit(val, FInteger | FNonNeg, false)) {
+ int weight = static_cast<int>(val->fValue);
+ if (!(weight % 100) && weight >= 100 && weight <= 900)
+ parsedValue = CSSPrimitiveValue::createIdentifier(CSSValue100 + weight / 100 - 1);
+ }
+ } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
+ expectComma = false;
+ m_valueList->next();
+ continue;
+ }
+
+ if (!parsedValue)
+ return false;
+
+ m_valueList->next();
+
+ if (values)
+ values->append(parsedValue.release());
+ else {
+ addProperty(CSSPropertyFontWeight, parsedValue.release(), important);
+ return true;
+ }
+ }
+
+ if (values && values->length()) {
+ m_hasFontFaceOnlyValues = true;
+ addProperty(CSSPropertyFontWeight, values.release(), important);
+ return true;
+ }
+
+ return false;
+}
+
+static bool isValidFormatFunction(CSSParserValue* val)
+{
+ CSSParserValueList* args = val->function->args;
+ return equalIgnoringCase(val->function->name, "format(") && (args->current()->unit == CSSPrimitiveValue::CSS_STRING || args->current()->unit == CSSPrimitiveValue::CSS_IDENT);
+}
+
+bool CSSParser::parseFontFaceSrc()
+{
+ RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
+ CSSParserValue* val;
+ bool expectComma = false;
+ bool allowFormat = false;
+ bool failed = false;
+ RefPtr<CSSFontFaceSrcValue> uriValue;
+ while ((val = m_valueList->current())) {
+ RefPtr<CSSFontFaceSrcValue> parsedValue;
+ if (val->unit == CSSPrimitiveValue::CSS_URI && !expectComma && m_styleSheet) {
+ // FIXME: The completeURL call should be done when using the CSSFontFaceSrcValue,
+ // not when creating it.
+ parsedValue = CSSFontFaceSrcValue::create(m_styleSheet->completeURL(val->string));
+ uriValue = parsedValue;
+ allowFormat = true;
+ expectComma = true;
+ } else if (val->unit == CSSParserValue::Function) {
+ // There are two allowed functions: local() and format().
+ CSSParserValueList* args = val->function->args;
+ if (args && args->size() == 1) {
+ if (equalIgnoringCase(val->function->name, "local(") && !expectComma) {
+ expectComma = true;
+ allowFormat = false;
+ CSSParserValue* a = args->current();
+ uriValue.clear();
+ parsedValue = CSSFontFaceSrcValue::createLocal(a->string);
+ } else if (allowFormat && uriValue && isValidFormatFunction(val)) {
+ expectComma = true;
+ allowFormat = false;
+ uriValue->setFormat(args->current()->string);
+ uriValue.clear();
+ m_valueList->next();
+ continue;
+ }
+ }
+ } else if (val->unit == CSSParserValue::Operator && val->iValue == ',' && expectComma) {
+ expectComma = false;
+ allowFormat = false;
+ uriValue.clear();
+ m_valueList->next();
+ continue;
+ }
+
+ if (parsedValue)
+ values->append(parsedValue.release());
+ else {
+ failed = true;
+ break;
+ }
+ m_valueList->next();
+ }
+
+ if (values->length() && !failed) {
+ addProperty(CSSPropertySrc, values.release(), m_important);
+ m_valueList->next();
+ return true;
+ }
+
+ return false;
+}
+
+bool CSSParser::parseFontFaceUnicodeRange()
+{
+ RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
+ bool failed = false;
+ bool operatorExpected = false;
+ for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
+ if (operatorExpected) {
+ if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
+ continue;
+ failed = true;
+ break;
+ }
+ if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
+ failed = true;
+ break;
+ }
+
+ String rangeString = m_valueList->current()->string;
+ UChar32 from = 0;
+ UChar32 to = 0;
+ unsigned length = rangeString.length();
+
+ if (length < 3) {
+ failed = true;
+ break;
+ }
+
+ unsigned i = 2;
+ while (i < length) {
+ UChar c = rangeString[i];
+ if (c == '-' || c == '?')
+ break;
+ from *= 16;
+ if (c >= '0' && c <= '9')
+ from += c - '0';
+ else if (c >= 'A' && c <= 'F')
+ from += 10 + c - 'A';
+ else if (c >= 'a' && c <= 'f')
+ from += 10 + c - 'a';
+ else {
+ failed = true;
+ break;
+ }
+ i++;
+ }
+ if (failed)
+ break;
+
+ if (i == length)
+ to = from;
+ else if (rangeString[i] == '?') {
+ unsigned span = 1;
+ while (i < length && rangeString[i] == '?') {
+ span *= 16;
+ from *= 16;
+ i++;
+ }
+ if (i < length)
+ failed = true;
+ to = from + span - 1;
+ } else {
+ if (length < i + 2) {
+ failed = true;
+ break;
+ }
+ i++;
+ while (i < length) {
+ UChar c = rangeString[i];
+ to *= 16;
+ if (c >= '0' && c <= '9')
+ to += c - '0';
+ else if (c >= 'A' && c <= 'F')
+ to += 10 + c - 'A';
+ else if (c >= 'a' && c <= 'f')
+ to += 10 + c - 'a';
+ else {
+ failed = true;
+ break;
+ }
+ i++;
+ }
+ if (failed)
+ break;
+ }
+ if (from <= to)
+ values->append(CSSUnicodeRangeValue::create(from, to));
+ }
+ if (failed || !values->length())
+ return false;
+ addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
+ return true;
+}
+
+static inline bool isCSSWhitespace(UChar c)
+{
+ return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f';
+}
+
+static inline bool parseColorInt(const UChar*& string, const UChar* end, UChar terminator, int& value)
+{
+ const UChar* current = string;
+ int localValue = 0;
+ bool negative = false;
+ while (current != end && isCSSWhitespace(*current))
+ current++;
+ if (current != end && *current == '-') {
+ negative = true;
+ current++;
+ }
+ if (current == end || !isASCIIDigit(*current))
+ return false;
+ while (current != end && isASCIIDigit(*current)) {
+ int newValue = localValue * 10 + *current++ - '0';
+ if (newValue >= 255) {
+ // Clamp values at 255.
+ localValue = 255;
+ while (current != end && isASCIIDigit(*current))
+ ++current;
+ break;
+ }
+ localValue = newValue;
+ }
+ while (current != end && isCSSWhitespace(*current))
+ current++;
+ if (current == end || *current++ != terminator)
+ return false;
+ // Clamp negative values at zero.
+ value = negative ? 0 : localValue;
+ string = current;
+ return true;
+}
+
+bool CSSParser::parseColor(const String &name, RGBA32& rgb, bool strict)
+{
+ const UChar* characters = name.characters();
+ unsigned length = name.length();
+
+ if (!strict && length >= 3) {
+ if (name[0] == '#') {
+ if (Color::parseHexColor(characters + 1, length - 1, rgb))
+ return true;
+ } else {
+ if (Color::parseHexColor(characters, length, rgb))
+ return true;
+ }
+ }
+
+ // Try rgb() syntax.
+ if (name.startsWith("rgb(")) {
+ const UChar* current = characters + 4;
+ const UChar* end = characters + length;
+ int red;
+ int green;
+ int blue;
+ if (!parseColorInt(current, end, ',', red))
+ return false;
+ if (!parseColorInt(current, end, ',', green))
+ return false;
+ if (!parseColorInt(current, end, ')', blue))
+ return false;
+ if (current != end)
+ return false;
+ rgb = makeRGB(red, green, blue);
+ return true;
+ }
+ // Try named colors.
+ Color tc;
+ tc.setNamedColor(name);
+ if (tc.isValid()) {
+ rgb = tc.rgb();
+ return true;
+ }
+ return false;
+}
+
+static inline int colorIntFromValue(CSSParserValue* v)
+{
+ if (v->fValue <= 0.0)
+ return 0;
+
+ if (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE) {
+ if (v->fValue >= 100.0)
+ return 255;
+ return static_cast<int>(v->fValue * 256.0 / 100.0);
+ }
+
+ if (v->fValue >= 255.0)
+ return 255;
+
+ return static_cast<int>(v->fValue);
+}
+
+bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
+{
+ CSSParserValueList* args = value->function->args;
+ CSSParserValue* v = args->current();
+ Units unitType = FUnknown;
+ // Get the first value and its type
+ if (validUnit(v, FInteger, true))
+ unitType = FInteger;
+ else if (validUnit(v, FPercent, true))
+ unitType = FPercent;
+ else
+ return false;
+ colorArray[0] = colorIntFromValue(v);
+ for (int i = 1; i < 3; i++) {
+ v = args->next();
+ if (v->unit != CSSParserValue::Operator && v->iValue != ',')
+ return false;
+ v = args->next();
+ if (!validUnit(v, unitType, true))
+ return false;
+ colorArray[i] = colorIntFromValue(v);
+ }
+ if (parseAlpha) {
+ v = args->next();
+ if (v->unit != CSSParserValue::Operator && v->iValue != ',')
+ return false;
+ v = args->next();
+ if (!validUnit(v, FNumber, true))
+ return false;
+ // Convert the floating pointer number of alpha to an integer in the range [0, 256),
+ // with an equal distribution across all 256 values.
+ colorArray[3] = static_cast<int>(max(0.0, min(1.0, v->fValue)) * nextafter(256.0, 0.0));
+ }
+ return true;
+}
+
+// The CSS3 specification defines the format of a HSL color as
+// hsl(<number>, <percent>, <percent>)
+// and with alpha, the format is
+// hsla(<number>, <percent>, <percent>, <number>)
+// The first value, HUE, is in an angle with a value between 0 and 360
+bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
+{
+ CSSParserValueList* args = value->function->args;
+ CSSParserValue* v = args->current();
+ // Get the first value
+ if (!validUnit(v, FNumber, true))
+ return false;
+ // normalize the Hue value and change it to be between 0 and 1.0
+ colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
+ for (int i = 1; i < 3; i++) {
+ v = args->next();
+ if (v->unit != CSSParserValue::Operator && v->iValue != ',')
+ return false;
+ v = args->next();
+ if (!validUnit(v, FPercent, true))
+ return false;
+ colorArray[i] = max(0.0, min(100.0, v->fValue)) / 100.0; // needs to be value between 0 and 1.0
+ }
+ if (parseAlpha) {
+ v = args->next();
+ if (v->unit != CSSParserValue::Operator && v->iValue != ',')
+ return false;
+ v = args->next();
+ if (!validUnit(v, FNumber, true))
+ return false;
+ colorArray[3] = max(0.0, min(1.0, v->fValue));
+ }
+ return true;
+}
+
+PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value)
+{
+ RGBA32 c = Color::transparent;
+ if (!parseColorFromValue(value ? value : m_valueList->current(), c))
+ return 0;
+ return CSSPrimitiveValue::createColor(c);
+}
+
+bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
+{
+ if (!m_strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
+ value->fValue >= 0. && value->fValue < 1000000.) {
+ String str = String::format("%06d", (int)(value->fValue+.5));
+ if (!CSSParser::parseColor(str, c, m_strict))
+ return false;
+ } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
+ value->unit == CSSPrimitiveValue::CSS_IDENT ||
+ (!m_strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
+ if (!CSSParser::parseColor(value->string, c, m_strict && value->unit == CSSPrimitiveValue::CSS_IDENT))
+ return false;
+ } else if (value->unit == CSSParserValue::Function &&
+ value->function->args != 0 &&
+ value->function->args->size() == 5 /* rgb + two commas */ &&
+ equalIgnoringCase(value->function->name, "rgb(")) {
+ int colorValues[3];
+ if (!parseColorParameters(value, colorValues, false))
+ return false;
+ c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
+ } else {
+ if (value->unit == CSSParserValue::Function &&
+ value->function->args != 0 &&
+ value->function->args->size() == 7 /* rgba + three commas */ &&
+ equalIgnoringCase(value->function->name, "rgba(")) {
+ int colorValues[4];
+ if (!parseColorParameters(value, colorValues, true))
+ return false;
+ c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
+ } else if (value->unit == CSSParserValue::Function &&
+ value->function->args != 0 &&
+ value->function->args->size() == 5 /* hsl + two commas */ &&
+ equalIgnoringCase(value->function->name, "hsl(")) {
+ double colorValues[3];
+ if (!parseHSLParameters(value, colorValues, false))
+ return false;
+ c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
+ } else if (value->unit == CSSParserValue::Function &&
+ value->function->args != 0 &&
+ value->function->args->size() == 7 /* hsla + three commas */ &&
+ equalIgnoringCase(value->function->name, "hsla(")) {
+ double colorValues[4];
+ if (!parseHSLParameters(value, colorValues, true))
+ return false;
+ c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+// This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return)
+// without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
+struct ShadowParseContext {
+ ShadowParseContext(CSSPropertyID prop)
+ : property(prop)
+ , allowX(true)
+ , allowY(false)
+ , allowBlur(false)
+ , allowSpread(false)
+ , allowColor(true)
+ , allowStyle(prop == CSSPropertyWebkitBoxShadow)
+ , allowBreak(true)
+ {
+ }
+
+ bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
+
+ void commitValue()
+ {
+ // Handle the ,, case gracefully by doing nothing.
+ if (x || y || blur || spread || color || style) {
+ if (!values)
+ values = CSSValueList::createCommaSeparated();
+
+ // Construct the current shadow value and add it to the list.
+ values->append(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
+ }
+
+ // Now reset for the next shadow value.
+ x = 0;
+ y = 0;
+ blur = 0;
+ spread = 0;
+ style = 0;
+ color = 0;
+
+ allowX = true;
+ allowColor = true;
+ allowBreak = true;
+ allowY = false;
+ allowBlur = false;
+ allowSpread = false;
+ allowStyle = property == CSSPropertyWebkitBoxShadow;
+ }
+
+ void commitLength(CSSParserValue* v)
+ {
+ RefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit);
+
+ if (allowX) {
+ x = val.release();
+ allowX = false;
+ allowY = true;
+ allowColor = false;
+ allowStyle = false;
+ allowBreak = false;
+ } else if (allowY) {
+ y = val.release();
+ allowY = false;
+ allowBlur = true;
+ allowColor = true;
+ allowStyle = property == CSSPropertyWebkitBoxShadow;
+ allowBreak = true;
+ } else if (allowBlur) {
+ blur = val.release();
+ allowBlur = false;
+ allowSpread = property == CSSPropertyWebkitBoxShadow;
+ } else if (allowSpread) {
+ spread = val.release();
+ allowSpread = false;
+ }
+ }
+
+ void commitColor(PassRefPtr<CSSPrimitiveValue> val)
+ {
+ color = val;
+ allowColor = false;
+ if (allowX) {
+ allowStyle = false;
+ allowBreak = false;
+ } else {
+ allowBlur = false;
+ allowSpread = false;
+ allowStyle = property == CSSPropertyWebkitBoxShadow;
+ }
+ }
+
+ void commitStyle(CSSParserValue* v)
+ {
+ style = CSSPrimitiveValue::createIdentifier(v->id);
+ allowStyle = false;
+ if (allowX)
+ allowBreak = false;
+ else {
+ allowBlur = false;
+ allowSpread = false;
+ allowColor = false;
+ }
+ }
+
+ CSSPropertyID property;
+
+ RefPtr<CSSValueList> values;
+ RefPtr<CSSPrimitiveValue> x;
+ RefPtr<CSSPrimitiveValue> y;
+ RefPtr<CSSPrimitiveValue> blur;
+ RefPtr<CSSPrimitiveValue> spread;
+ RefPtr<CSSPrimitiveValue> style;
+ RefPtr<CSSPrimitiveValue> color;
+
+ bool allowX;
+ bool allowY;
+ bool allowBlur;
+ bool allowSpread;
+ bool allowColor;
+ bool allowStyle;
+ bool allowBreak;
+};
+
+bool CSSParser::parseShadow(int propId, bool important)
+{
+ ShadowParseContext context(static_cast<CSSPropertyID>(propId));
+ CSSParserValue* val;
+ while ((val = m_valueList->current())) {
+ // Check for a comma break first.
+ if (val->unit == CSSParserValue::Operator) {
+ if (val->iValue != ',' || !context.allowBreak)
+ // Other operators aren't legal or we aren't done with the current shadow
+ // value. Treat as invalid.
+ return false;
+#if ENABLE(SVG)
+ // -webkit-svg-shadow does not support multiple values.
+ if (static_cast<CSSPropertyID>(propId) == CSSPropertyWebkitSvgShadow)
+ return false;
+#endif
+ // The value is good. Commit it.
+ context.commitValue();
+ } else if (validUnit(val, FLength, true)) {
+ // We required a length and didn't get one. Invalid.
+ if (!context.allowLength())
+ return false;
+
+ // A length is allowed here. Construct the value and add it.
+ context.commitLength(val);
+ } else if (val->id == CSSValueInset) {
+ if (!context.allowStyle)
+ return false;
+
+ context.commitStyle(val);
+ } else {
+ // The only other type of value that's ok is a color value.
+ RefPtr<CSSPrimitiveValue> parsedColor;
+ bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu ||
+ (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && !m_strict));
+ if (isColor) {
+ if (!context.allowColor)
+ return false;
+ parsedColor = CSSPrimitiveValue::createIdentifier(val->id);
+ }
+
+ if (!parsedColor)
+ // It's not built-in. Try to parse it as a color.
+ parsedColor = parseColor(val);
+
+ if (!parsedColor || !context.allowColor)
+ return false; // This value is not a color or length and is invalid or
+ // it is a color, but a color isn't allowed at this point.
+
+ context.commitColor(parsedColor.release());
+ }
+
+ m_valueList->next();
+ }
+
+ if (context.allowBreak) {
+ context.commitValue();
+ if (context.values->length()) {
+ addProperty(propId, context.values.release(), important);
+ m_valueList->next();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CSSParser::parseReflect(int propId, bool important)
+{
+ // box-reflect: <direction> <offset> <mask>
+
+ // Direction comes first.
+ CSSParserValue* val = m_valueList->current();
+ CSSReflectionDirection direction;
+ switch (val->id) {
+ case CSSValueAbove:
+ direction = ReflectionAbove;
+ break;
+ case CSSValueBelow:
+ direction = ReflectionBelow;
+ break;
+ case CSSValueLeft:
+ direction = ReflectionLeft;
+ break;
+ case CSSValueRight:
+ direction = ReflectionRight;
+ break;
+ default:
+ return false;
+ }
+
+ // The offset comes next.
+ val = m_valueList->next();
+ RefPtr<CSSPrimitiveValue> offset;
+ if (!val)
+ offset = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_PX);
+ else {
+ if (!validUnit(val, FLength | FPercent, m_strict))
+ return false;
+ offset = CSSPrimitiveValue::create(val->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(val->unit));
+ }
+
+ // Now for the mask.
+ RefPtr<CSSValue> mask;
+ val = m_valueList->next();
+ if (val) {
+ if (!parseBorderImage(propId, important, mask))
+ return false;
+ }
+
+ RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction, offset.release(), mask.release());
+ addProperty(propId, reflectValue.release(), important);
+ m_valueList->next();
+ return true;
+}
+
+struct BorderImageParseContext {
+ BorderImageParseContext()
+ : m_allowBreak(false)
+ , m_allowNumber(false)
+ , m_allowSlash(false)
+ , m_allowWidth(false)
+ , m_allowRule(false)
+ , m_borderTop(0)
+ , m_borderRight(0)
+ , m_borderBottom(0)
+ , m_borderLeft(0)
+ , m_horizontalRule(0)
+ , m_verticalRule(0)
+ {}
+
+ bool allowBreak() const { return m_allowBreak; }
+ bool allowNumber() const { return m_allowNumber; }
+ bool allowSlash() const { return m_allowSlash; }
+ bool allowWidth() const { return m_allowWidth; }
+ bool allowRule() const { return m_allowRule; }
+
+ void commitImage(PassRefPtr<CSSValue> image) { m_image = image; m_allowNumber = true; }
+ void commitNumber(CSSParserValue* v)
+ {
+ PassRefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit);
+ if (!m_top)
+ m_top = val;
+ else if (!m_right)
+ m_right = val;
+ else if (!m_bottom)
+ m_bottom = val;
+ else {
+ ASSERT(!m_left);
+ m_left = val;
+ }
+
+ m_allowBreak = m_allowSlash = m_allowRule = true;
+ m_allowNumber = !m_left;
+ }
+ void commitSlash() { m_allowBreak = m_allowSlash = m_allowNumber = false; m_allowWidth = true; }
+ void commitWidth(CSSParserValue* val)
+ {
+ if (!m_borderTop)
+ m_borderTop = val;
+ else if (!m_borderRight)
+ m_borderRight = val;
+ else if (!m_borderBottom)
+ m_borderBottom = val;
+ else {
+ ASSERT(!m_borderLeft);
+ m_borderLeft = val;
+ }
+
+ m_allowBreak = m_allowRule = true;
+ m_allowWidth = !m_borderLeft;
+ }
+ void commitRule(int keyword)
+ {
+ if (!m_horizontalRule)
+ m_horizontalRule = keyword;
+ else if (!m_verticalRule)
+ m_verticalRule = keyword;
+ m_allowRule = !m_verticalRule;
+ }
+ PassRefPtr<CSSValue> commitBorderImage(CSSParser* p, bool important)
+ {
+ // We need to clone and repeat values for any omissions.
+ if (!m_right) {
+ m_right = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
+ m_bottom = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
+ m_left = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
+ }
+ if (!m_bottom) {
+ m_bottom = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
+ m_left = CSSPrimitiveValue::create(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType());
+ }
+ if (!m_left)
+ m_left = CSSPrimitiveValue::create(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType());
+
+ // Now build a rect value to hold all four of our primitive values.
+ RefPtr<Rect> rect = Rect::create();
+ rect->setTop(m_top);
+ rect->setRight(m_right);
+ rect->setBottom(m_bottom);
+ rect->setLeft(m_left);
+
+ // Fill in STRETCH as the default if it wasn't specified.
+ if (!m_horizontalRule)
+ m_horizontalRule = CSSValueStretch;
+
+ // The vertical rule should match the horizontal rule if unspecified.
+ if (!m_verticalRule)
+ m_verticalRule = m_horizontalRule;
+
+ // 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
+ // list and then make our parsing machinery do the parsing.
+ if (m_borderTop) {
+ CSSParserValueList newList;
+ newList.addValue(*m_borderTop);
+ if (m_borderRight)
+ newList.addValue(*m_borderRight);
+ if (m_borderBottom)
+ newList.addValue(*m_borderBottom);
+ if (m_borderLeft)
+ newList.addValue(*m_borderLeft);
+ CSSParserValueList* oldList = p->m_valueList;
+ p->m_valueList = &newList;
+ p->parseValue(CSSPropertyBorderWidth, important);
+ p->m_valueList = oldList;
+ }
+
+ // Make our new border image value now.
+ return CSSBorderImageValue::create(m_image, rect.release(), m_horizontalRule, m_verticalRule);
+ }
+
+ bool m_allowBreak;
+ bool m_allowNumber;
+ bool m_allowSlash;
+ bool m_allowWidth;
+ bool m_allowRule;
+
+ RefPtr<CSSValue> m_image;
+
+ RefPtr<CSSPrimitiveValue> m_top;
+ RefPtr<CSSPrimitiveValue> m_right;
+ RefPtr<CSSPrimitiveValue> m_bottom;
+ RefPtr<CSSPrimitiveValue> m_left;
+
+ CSSParserValue* m_borderTop;
+ CSSParserValue* m_borderRight;
+ CSSParserValue* m_borderBottom;
+ CSSParserValue* m_borderLeft;
+
+ int m_horizontalRule;
+ int m_verticalRule;
+};
+
+bool CSSParser::parseBorderImage(int propId, bool important, RefPtr<CSSValue>& result)
+{
+ // Look for an image initially. If the first value is not a URI, then we're done.
+ BorderImageParseContext context;
+ CSSParserValue* val = m_valueList->current();
+ if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
+ // FIXME: The completeURL call should be done when using the CSSImageValue,
+ // not when creating it.
+ context.commitImage(CSSImageValue::create(m_styleSheet->completeURL(val->string)));
+ } else if (val->unit == CSSParserValue::Function) {
+ RefPtr<CSSValue> value;
+ if ((equalIgnoringCase(val->function->name, "-webkit-gradient(") && parseGradient(value)) ||
+ (equalIgnoringCase(val->function->name, "-webkit-canvas(") && parseCanvas(value)))
+ context.commitImage(value);
+ else
+ return false;
+ } else
+ return false;
+
+ while ((val = m_valueList->next())) {
+ if (context.allowNumber() && validUnit(val, FInteger | FNonNeg | FPercent, true)) {
+ context.commitNumber(val);
+ } else if (propId == CSSPropertyWebkitBorderImage && context.allowSlash() && val->unit == CSSParserValue::Operator && val->iValue == '/') {
+ context.commitSlash();
+ } else if (context.allowWidth() &&
+ (val->id == CSSValueThin || val->id == CSSValueMedium || val->id == CSSValueThick || validUnit(val, FLength, m_strict))) {
+ context.commitWidth(val);
+ } else if (context.allowRule() &&
+ (val->id == CSSValueStretch || val->id == CSSValueRound || val->id == CSSValueRepeat)) {
+ context.commitRule(val->id);
+ } else {
+ // Something invalid was encountered.
+ return false;
+ }
+ }
+
+ if (context.allowNumber() && propId != CSSPropertyWebkitBorderImage) {
+ // Allow the slices to be omitted for images that don't fit to a border. We just set the slices to be 0.
+ context.m_top = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_NUMBER);
+ context.m_allowBreak = true;
+ }
+
+ if (context.allowBreak()) {
+ // Need to fully commit as a single value.
+ result = context.commitBorderImage(this, important);
+ return true;
+ }
+
+ return false;
+}
+
+static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4])
+{
+ if (radii[3])
+ return;
+ if (!radii[2]) {
+ if (!radii[1])
+ radii[1] = radii[0];
+ radii[2] = radii[0];
+ }
+ radii[3] = radii[1];
+}
+
+bool CSSParser::parseBorderRadius(int propId, bool important)
+{
+ unsigned num = m_valueList->size();
+ if (num > 9)
+ return false;
+
+ RefPtr<CSSPrimitiveValue> radii[2][4];
+
+ unsigned indexAfterSlash = 0;
+ for (unsigned i = 0; i < num; ++i) {
+ CSSParserValue* value = m_valueList->valueAt(i);
+ if (value->unit == CSSParserValue::Operator) {
+ if (value->iValue != '/')
+ return false;
+
+ if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
+ return false;
+
+ indexAfterSlash = i + 1;
+ completeBorderRadii(radii[0]);
+ continue;
+ }
+
+ if (i - indexAfterSlash >= 4)
+ return false;
+
+ if (!validUnit(value, FLength, m_strict))
+ return false;
+
+ RefPtr<CSSPrimitiveValue> radius = CSSPrimitiveValue::create(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
+
+ if (!indexAfterSlash) {
+ radii[0][i] = radius;
+
+ // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
+ if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
+ indexAfterSlash = 1;
+ completeBorderRadii(radii[0]);
+ }
+ } else
+ radii[1][i - indexAfterSlash] = radius.release();
+ }
+
+ if (!indexAfterSlash) {
+ completeBorderRadii(radii[0]);
+ for (unsigned i = 0; i < 4; ++i)
+ radii[1][i] = radii[0][i];
+ } else
+ completeBorderRadii(radii[1]);
+
+ addProperty(CSSPropertyBorderTopLeftRadius, CSSPrimitiveValue::create(Pair::create(radii[0][0].release(), radii[1][0].release())), important);
+ addProperty(CSSPropertyBorderTopRightRadius, CSSPrimitiveValue::create(Pair::create(radii[0][1].release(), radii[1][1].release())), important);
+ addProperty(CSSPropertyBorderBottomRightRadius, CSSPrimitiveValue::create(Pair::create(radii[0][2].release(), radii[1][2].release())), important);
+ addProperty(CSSPropertyBorderBottomLeftRadius, CSSPrimitiveValue::create(Pair::create(radii[0][3].release(), radii[1][3].release())), important);
+ return true;
+}
+
+bool CSSParser::parseCounter(int propId, int defaultValue, bool important)
+{
+ enum { ID, VAL } state = ID;
+
+ RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
+ RefPtr<CSSPrimitiveValue> counterName;
+
+ while (true) {
+ CSSParserValue* val = m_valueList->current();
+ switch (state) {
+ case ID:
+ if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
+ counterName = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
+ state = VAL;
+ m_valueList->next();
+ continue;
+ }
+ break;
+ case VAL: {
+ int i = defaultValue;
+ if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
+ i = (int)val->fValue;
+ m_valueList->next();
+ }
+
+ list->append(CSSPrimitiveValue::create(Pair::create(counterName.release(),
+ CSSPrimitiveValue::create(i, CSSPrimitiveValue::CSS_NUMBER))));
+ state = ID;
+ continue;
+ }
+ }
+ break;
+ }
+
+ if (list->length() > 0) {
+ addProperty(propId, list.release(), important);
+ return true;
+ }
+
+ return false;
+}
+
+static PassRefPtr<CSSPrimitiveValue> parseGradientPoint(CSSParserValue* a, bool horizontal)
+{
+ RefPtr<CSSPrimitiveValue> result;
+ if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
+ if ((equalIgnoringCase(a->string, "left") && horizontal)
+ || (equalIgnoringCase(a->string, "top") && !horizontal))
+ result = CSSPrimitiveValue::create(0., CSSPrimitiveValue::CSS_PERCENTAGE);
+ else if ((equalIgnoringCase(a->string, "right") && horizontal)
+ || (equalIgnoringCase(a->string, "bottom") && !horizontal))
+ result = CSSPrimitiveValue::create(100., CSSPrimitiveValue::CSS_PERCENTAGE);
+ else if (equalIgnoringCase(a->string, "center"))
+ result = CSSPrimitiveValue::create(50., CSSPrimitiveValue::CSS_PERCENTAGE);
+ } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
+ result = CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit);
+ return result;
+}
+
+static bool parseGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
+{
+ if (a->unit != CSSParserValue::Function)
+ return false;
+
+ if (!equalIgnoringCase(a->function->name, "from(") &&
+ !equalIgnoringCase(a->function->name, "to(") &&
+ !equalIgnoringCase(a->function->name, "color-stop("))
+ return false;
+
+ CSSParserValueList* args = a->function->args;
+ if (!args)
+ return false;
+
+ if (equalIgnoringCase(a->function->name, "from(")
+ || equalIgnoringCase(a->function->name, "to(")) {
+ // The "from" and "to" stops expect 1 argument.
+ if (args->size() != 1)
+ return false;
+
+ if (equalIgnoringCase(a->function->name, "from("))
+ stop.m_stop = 0.f;
+ else
+ stop.m_stop = 1.f;
+
+ int id = args->current()->id;
+ if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
+ stop.m_color = CSSPrimitiveValue::createIdentifier(id);
+ else
+ stop.m_color = p->parseColor(args->current());
+ if (!stop.m_color)
+ return false;
+ }
+
+ // The "color-stop" function expects 3 arguments.
+ if (equalIgnoringCase(a->function->name, "color-stop(")) {
+ if (args->size() != 3)
+ return false;
+
+ CSSParserValue* stopArg = args->current();
+ if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
+ stop.m_stop = (float)stopArg->fValue / 100.f;
+ else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
+ stop.m_stop = (float)stopArg->fValue;
+ else
+ return false;
+
+ stopArg = args->next();
+ if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
+ return false;
+
+ stopArg = args->next();
+ int id = stopArg->id;
+ if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
+ stop.m_color = CSSPrimitiveValue::createIdentifier(id);
+ else
+ stop.m_color = p->parseColor(stopArg);
+ if (!stop.m_color)
+ return false;
+ }
+
+ return true;
+}
+
+bool CSSParser::parseGradient(RefPtr<CSSValue>& gradient)
+{
+ RefPtr<CSSGradientValue> result = CSSGradientValue::create();
+
+ // Walk the arguments.
+ CSSParserValueList* args = m_valueList->current()->function->args;
+ if (!args || args->size() == 0)
+ return false;
+
+ // The first argument is the gradient type. It is an identifier.
+ CSSParserValue* a = args->current();
+ if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
+ return false;
+ if (equalIgnoringCase(a->string, "linear"))
+ result->setType(CSSLinearGradient);
+ else if (equalIgnoringCase(a->string, "radial"))
+ result->setType(CSSRadialGradient);
+ else
+ return false;
+
+ // Comma.
+ a = args->next();
+ if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
+ return false;
+
+ // Next comes the starting point for the gradient as an x y pair. There is no
+ // comma between the x and the y values.
+ // First X. It can be left, right, number or percent.
+ a = args->next();
+ if (!a)
+ return false;
+ RefPtr<CSSPrimitiveValue> point = parseGradientPoint(a, true);
+ if (!point)
+ return false;
+ result->setFirstX(point.release());
+
+ // First Y. It can be top, bottom, number or percent.
+ a = args->next();
+ if (!a)
+ return false;
+ point = parseGradientPoint(a, false);
+ if (!point)
+ return false;
+ result->setFirstY(point.release());
+
+ // Comma after the first point.
+ a = args->next();
+ if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
+ return false;
+
+ // For radial gradients only, we now expect a numeric radius.
+ if (result->type() == CSSRadialGradient) {
+ a = args->next();
+ if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
+ return false;
+ result->setFirstRadius(CSSPrimitiveValue::create(a->fValue, CSSPrimitiveValue::CSS_NUMBER));
+
+ // Comma after the first radius.
+ a = args->next();
+ if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
+ return false;
+ }
+
+ // Next is the ending point for the gradient as an x, y pair.
+ // Second X. It can be left, right, number or percent.
+ a = args->next();
+ if (!a)
+ return false;
+ point = parseGradientPoint(a, true);
+ if (!point)
+ return false;
+ result->setSecondX(point.release());
+
+ // Second Y. It can be top, bottom, number or percent.
+ a = args->next();
+ if (!a)
+ return false;
+ point = parseGradientPoint(a, false);
+ if (!point)
+ return false;
+ result->setSecondY(point.release());
+
+ // For radial gradients only, we now expect the second radius.
+ if (result->type() == CSSRadialGradient) {
+ // Comma after the second point.
+ a = args->next();
+ if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
+ return false;
+
+ a = args->next();
+ if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
+ return false;
+ result->setSecondRadius(CSSPrimitiveValue::create(a->fValue, CSSPrimitiveValue::CSS_NUMBER));
+ }
+
+ // We now will accept any number of stops (0 or more).
+ a = args->next();
+ while (a) {
+ // Look for the comma before the next stop.
+ if (a->unit != CSSParserValue::Operator || a->iValue != ',')
+ return false;
+
+ // Now examine the stop itself.
+ a = args->next();
+ if (!a)
+ return false;
+
+ // The function name needs to be one of "from", "to", or "color-stop."
+ CSSGradientColorStop stop;
+ if (!parseGradientColorStop(this, a, stop))
+ return false;
+ result->addStop(stop);
+
+ // Advance
+ a = args->next();
+ }
+
+ gradient = result.release();
+ return true;
+}
+
+bool CSSParser::parseCanvas(RefPtr<CSSValue>& canvas)
+{
+ RefPtr<CSSCanvasValue> result = CSSCanvasValue::create();
+
+ // Walk the arguments.
+ CSSParserValueList* args = m_valueList->current()->function->args;
+ if (!args || args->size() != 1)
+ return false;
+
+ // The first argument is the canvas name. It is an identifier.
+ CSSParserValue* a = args->current();
+ if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
+ return false;
+ result->setName(a->string);
+ canvas = result;
+ return true;
+}
+
+class TransformOperationInfo {
+public:
+ TransformOperationInfo(const CSSParserString& name)
+ : m_type(WebKitCSSTransformValue::UnknownTransformOperation)
+ , m_argCount(1)
+ , m_allowSingleArgument(false)
+ , m_unit(CSSParser::FUnknown)
+ {
+ if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "scalex(") || equalIgnoringCase(name, "scaley(") || equalIgnoringCase(name, "scalez(")) {
+ m_unit = CSSParser::FNumber;
+ if (equalIgnoringCase(name, "scale("))
+ m_type = WebKitCSSTransformValue::ScaleTransformOperation;
+ else if (equalIgnoringCase(name, "scalex("))
+ m_type = WebKitCSSTransformValue::ScaleXTransformOperation;
+ else if (equalIgnoringCase(name, "scaley("))
+ m_type = WebKitCSSTransformValue::ScaleYTransformOperation;
+ else
+ m_type = WebKitCSSTransformValue::ScaleZTransformOperation;
+ } else if (equalIgnoringCase(name, "scale3d(")) {
+ m_type = WebKitCSSTransformValue::Scale3DTransformOperation;
+ m_argCount = 5;
+ m_unit = CSSParser::FNumber;
+ } else if (equalIgnoringCase(name, "rotate(")) {
+ m_type = WebKitCSSTransformValue::RotateTransformOperation;
+ m_unit = CSSParser::FAngle;
+ } else if (equalIgnoringCase(name, "rotatex(") ||
+ equalIgnoringCase(name, "rotatey(") ||
+ equalIgnoringCase(name, "rotatez(")) {
+ m_unit = CSSParser::FAngle;
+ if (equalIgnoringCase(name, "rotatex("))
+ m_type = WebKitCSSTransformValue::RotateXTransformOperation;
+ else if (equalIgnoringCase(name, "rotatey("))
+ m_type = WebKitCSSTransformValue::RotateYTransformOperation;
+ else
+ m_type = WebKitCSSTransformValue::RotateZTransformOperation;
+ } else if (equalIgnoringCase(name, "rotate3d(")) {
+ m_type = WebKitCSSTransformValue::Rotate3DTransformOperation;
+ m_argCount = 7;
+ m_unit = CSSParser::FNumber;
+ } else if (equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "skewx(") || equalIgnoringCase(name, "skewy(")) {
+ m_unit = CSSParser::FAngle;
+ if (equalIgnoringCase(name, "skew("))
+ m_type = WebKitCSSTransformValue::SkewTransformOperation;
+ else if (equalIgnoringCase(name, "skewx("))
+ m_type = WebKitCSSTransformValue::SkewXTransformOperation;
+ else
+ m_type = WebKitCSSTransformValue::SkewYTransformOperation;
+ } else if (equalIgnoringCase(name, "translate(") || equalIgnoringCase(name, "translatex(") || equalIgnoringCase(name, "translatey(") || equalIgnoringCase(name, "translatez(")) {
+ m_unit = CSSParser::FLength | CSSParser::FPercent;
+ if (equalIgnoringCase(name, "translate("))
+ m_type = WebKitCSSTransformValue::TranslateTransformOperation;
+ else if (equalIgnoringCase(name, "translatex("))
+ m_type = WebKitCSSTransformValue::TranslateXTransformOperation;
+ else if (equalIgnoringCase(name, "translatey("))
+ m_type = WebKitCSSTransformValue::TranslateYTransformOperation;
+ else
+ m_type = WebKitCSSTransformValue::TranslateZTransformOperation;
+ } else if (equalIgnoringCase(name, "translate3d(")) {
+ m_type = WebKitCSSTransformValue::Translate3DTransformOperation;
+ m_argCount = 5;
+ m_unit = CSSParser::FLength | CSSParser::FPercent;
+ } else if (equalIgnoringCase(name, "matrix(")) {
+ m_type = WebKitCSSTransformValue::MatrixTransformOperation;
+ m_argCount = 11;
+ m_unit = CSSParser::FNumber;
+ } else if (equalIgnoringCase(name, "matrix3d(")) {
+ m_type = WebKitCSSTransformValue::Matrix3DTransformOperation;
+ m_argCount = 31;
+ m_unit = CSSParser::FNumber;
+ } else if (equalIgnoringCase(name, "perspective(")) {
+ m_type = WebKitCSSTransformValue::PerspectiveTransformOperation;
+ m_unit = CSSParser::FNumber;
+ }
+
+ if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "translate(")) {
+ m_allowSingleArgument = true;
+ m_argCount = 3;
+ }
+ }
+
+ WebKitCSSTransformValue::TransformOperationType type() const { return m_type; }
+ unsigned argCount() const { return m_argCount; }
+ CSSParser::Units unit() const { return m_unit; }
+
+ bool unknown() const { return m_type == WebKitCSSTransformValue::UnknownTransformOperation; }
+ bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
+
+private:
+ WebKitCSSTransformValue::TransformOperationType m_type;
+ unsigned m_argCount;
+ bool m_allowSingleArgument;
+ CSSParser::Units m_unit;
+};
+
+PassRefPtr<CSSValueList> CSSParser::parseTransform()
+{
+ if (!m_valueList)
+ return 0;
+
+ // The transform is a list of functional primitives that specify transform operations.
+ // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation.
+ RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
+ for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
+ if (value->unit != CSSParserValue::Function || !value->function)
+ return 0;
+
+ // Every primitive requires at least one argument.
+ CSSParserValueList* args = value->function->args;
+ if (!args)
+ return 0;
+
+ // See if the specified primitive is one we understand.
+ TransformOperationInfo info(value->function->name);
+ if (info.unknown())
+ return 0;
+
+ if (!info.hasCorrectArgCount(args->size()))
+ return 0;
+
+ // Create the new WebKitCSSTransformValue for this operation and add it to our list.
+ RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(info.type());
+ list->append(transformValue);
+
+ // Snag our values.
+ CSSParserValue* a = args->current();
+ unsigned argNumber = 0;
+ while (a) {
+ CSSParser::Units unit = info.unit();
+
+ // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
+ if (info.type() == WebKitCSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
+ if (!validUnit(a, FAngle, true))
+ return 0;
+ } else if (!validUnit(a, unit, true))
+ return 0;
+
+ // Add the value to the current transform operation.
+ transformValue->append(CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit));
+
+ a = args->next();
+ if (!a)
+ break;
+ if (a->unit != CSSParserValue::Operator || a->iValue != ',')
+ return 0;
+ a = args->next();
+
+ argNumber++;
+ }
+ }
+
+ return list.release();
+}
+
+bool CSSParser::parseTransformOrigin(int propId, int& propId1, int& propId2, int& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
+{
+ propId1 = propId;
+ propId2 = propId;
+ propId3 = propId;
+ if (propId == CSSPropertyWebkitTransformOrigin) {
+ propId1 = CSSPropertyWebkitTransformOriginX;
+ propId2 = CSSPropertyWebkitTransformOriginY;
+ propId3 = CSSPropertyWebkitTransformOriginZ;
+ }
+
+ switch (propId) {
+ case CSSPropertyWebkitTransformOrigin:
+ parseTransformOriginShorthand(value, value2, value3);
+ // parseTransformOriginShorthand advances the m_valueList pointer
+ break;
+ case CSSPropertyWebkitTransformOriginX: {
+ bool xFound = false, yFound = true;
+ value = parseFillPositionXY(xFound, yFound);
+ if (value)
+ m_valueList->next();
+ break;
+ }
+ case CSSPropertyWebkitTransformOriginY: {
+ bool xFound = true, yFound = false;
+ value = parseFillPositionXY(xFound, yFound);
+ if (value)
+ m_valueList->next();
+ break;
+ }
+ case CSSPropertyWebkitTransformOriginZ: {
+ if (validUnit(m_valueList->current(), FLength, m_strict))
+ value = CSSPrimitiveValue::create(m_valueList->current()->fValue, (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit);
+ if (value)
+ m_valueList->next();
+ break;
+ }
+ }
+
+ return value;
+}
+
+bool CSSParser::parsePerspectiveOrigin(int propId, int& propId1, int& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2)
+{
+ propId1 = propId;
+ propId2 = propId;
+ if (propId == CSSPropertyWebkitPerspectiveOrigin) {
+ propId1 = CSSPropertyWebkitPerspectiveOriginX;
+ propId2 = CSSPropertyWebkitPerspectiveOriginY;
+ }
+
+ switch (propId) {
+ case CSSPropertyWebkitPerspectiveOrigin:
+ parseFillPosition(value, value2);
+ break;
+ case CSSPropertyWebkitPerspectiveOriginX: {
+ bool xFound = false, yFound = true;
+ value = parseFillPositionXY(xFound, yFound);
+ if (value)
+ m_valueList->next();
+ break;
+ }
+ case CSSPropertyWebkitPerspectiveOriginY: {
+ bool xFound = true, yFound = false;
+ value = parseFillPositionXY(xFound, yFound);
+ if (value)
+ m_valueList->next();
+ break;
+ }
+ }
+
+ return value;
+}
+
+static inline int yyerror(const char*) { return 1; }
+
+#define END_TOKEN 0
+
+#include "CSSGrammar.h"
+
+int CSSParser::lex(void* yylvalWithoutType)
+{
+ YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType);
+ int length;
+
+ lex();
+
+ UChar* t = text(&length);
+
+ switch (token()) {
+ case WHITESPACE:
+ case SGML_CD:
+ case INCLUDES:
+ case DASHMATCH:
+ break;
+
+ case URI:
+ case STRING:
+ case IDENT:
+ case NTH:
+ case HEX:
+ case IDSEL:
+ case DIMEN:
+ case UNICODERANGE:
+ case FUNCTION:
+ case NOTFUNCTION:
+ case VARCALL:
+ yylval->string.characters = t;
+ yylval->string.length = length;
+ break;
+
+ case IMPORT_SYM:
+ case PAGE_SYM:
+ case MEDIA_SYM:
+ case FONT_FACE_SYM:
+ case CHARSET_SYM:
+ case NAMESPACE_SYM:
+ case WEBKIT_KEYFRAMES_SYM:
+
+ case IMPORTANT_SYM:
+ break;
+
+ case QEMS:
+ length--;
+ case GRADS:
+ case TURNS:
+ length--;
+ case DEGS:
+ case RADS:
+ case KHERZ:
+ case REMS:
+ length--;
+ case MSECS:
+ case HERZ:
+ case EMS:
+ case EXS:
+ case PXS:
+ case CMS:
+ case MMS:
+ case INS:
+ case PTS:
+ case PCS:
+ length--;
+ case SECS:
+ case PERCENTAGE:
+ length--;
+ case FLOATTOKEN:
+ case INTEGER:
+ yylval->number = charactersToDouble(t, length);
+ break;
+
+ default:
+ break;
+ }
+
+ return token();
+}
+
+void CSSParser::recheckAtKeyword(const UChar* str, int len)
+{
+ String ruleName(str, len);
+ if (equalIgnoringCase(ruleName, "@import"))
+ yyTok = IMPORT_SYM;
+ else if (equalIgnoringCase(ruleName, "@page"))
+ yyTok = PAGE_SYM;
+ else if (equalIgnoringCase(ruleName, "@media"))
+ yyTok = MEDIA_SYM;
+ else if (equalIgnoringCase(ruleName, "@font-face"))
+ yyTok = FONT_FACE_SYM;
+ else if (equalIgnoringCase(ruleName, "@charset"))
+ yyTok = CHARSET_SYM;
+ else if (equalIgnoringCase(ruleName, "@namespace"))
+ yyTok = NAMESPACE_SYM;
+ else if (equalIgnoringCase(ruleName, "@-webkit-keyframes"))
+ yyTok = WEBKIT_KEYFRAMES_SYM;
+ else if (equalIgnoringCase(ruleName, "@-webkit-mediaquery"))
+ yyTok = WEBKIT_MEDIAQUERY_SYM;
+ // FIXME: Add CSS Variables if we ever decide to turn it back on.
+}
+
+UChar* CSSParser::text(int *length)
+{
+ UChar* start = yytext;
+ int l = yyleng;
+ switch (yyTok) {
+ case STRING:
+ l--;
+ /* nobreak */
+ case HEX:
+ case IDSEL:
+ start++;
+ l--;
+ break;
+ case URI:
+ // "url("{w}{string}{w}")"
+ // "url("{w}{url}{w}")"
+ // strip "url(" and ")"
+ start += 4;
+ l -= 5;
+ // strip {w}
+ while (l && isCSSWhitespace(*start)) {
+ ++start;
+ --l;
+ }
+ while (l && isCSSWhitespace(start[l - 1]))
+ --l;
+ if (l && (*start == '"' || *start == '\'')) {
+ ASSERT(l >= 2 && start[l - 1] == *start);
+ ++start;
+ l -= 2;
+ }
+ break;
+ case VARCALL:
+ // "-webkit-var("{w}{ident}{w}")"
+ // strip "-webkit-var(" and ")"
+ start += 12;
+ l -= 13;
+ // strip {w}
+ while (l && isCSSWhitespace(*start)) {
+ ++start;
+ --l;
+ }
+ while (l && isCSSWhitespace(start[l - 1]))
+ --l;
+ break;
+ default:
+ break;
+ }
+
+ // process escapes
+ UChar* out = start;
+ UChar* escape = 0;
+
+ bool sawEscape = false;
+
+ for (int i = 0; i < l; i++) {
+ UChar* current = start + i;
+ if (escape == current - 1) {
+ if (isASCIIHexDigit(*current))
+ continue;
+ if (yyTok == STRING &&
+ (*current == '\n' || *current == '\r' || *current == '\f')) {
+ // ### handle \r\n case
+ if (*current != '\r')
+ escape = 0;
+ continue;
+ }
+ // in all other cases copy the char to output
+ // ###
+ *out++ = *current;
+ escape = 0;
+ continue;
+ }
+ if (escape == current - 2 && yyTok == STRING &&
+ *(current-1) == '\r' && *current == '\n') {
+ escape = 0;
+ continue;
+ }
+ if (escape > current - 7 && isASCIIHexDigit(*current))
+ continue;
+ if (escape) {
+ // add escaped char
+ unsigned uc = 0;
+ escape++;
+ while (escape < current) {
+ uc *= 16;
+ uc += toASCIIHexValue(*escape);
+ escape++;
+ }
+ // can't handle chars outside ucs2
+ if (uc > 0xffff)
+ uc = 0xfffd;
+ *out++ = uc;
+ escape = 0;
+ if (isCSSWhitespace(*current))
+ continue;
+ }
+ if (!escape && *current == '\\') {
+ escape = current;
+ sawEscape = true;
+ continue;
+ }
+ *out++ = *current;
+ }
+ if (escape) {
+ // add escaped char
+ unsigned uc = 0;
+ escape++;
+ while (escape < start+l) {
+ uc *= 16;
+ uc += toASCIIHexValue(*escape);
+ escape++;
+ }
+ // can't handle chars outside ucs2
+ if (uc > 0xffff)
+ uc = 0xfffd;
+ *out++ = uc;
+ }
+
+ *length = out - start;
+
+ // If we have an unrecognized @-keyword, and if we handled any escapes at all, then
+ // we should attempt to adjust yyTok to the correct type.
+ if (yyTok == ATKEYWORD && sawEscape)
+ recheckAtKeyword(start, *length);
+
+ return start;
+}
+
+void CSSParser::countLines()
+{
+ for (UChar* current = yytext; current < yytext + yyleng; ++current) {
+ if (*current == '\n')
+ ++m_lineNumber;
+ }
+}
+
+CSSSelector* CSSParser::createFloatingSelector()
+{
+ CSSSelector* selector = fastNew<CSSSelector>();
+ m_floatingSelectors.add(selector);
+ return selector;
+}
+
+CSSSelector* CSSParser::sinkFloatingSelector(CSSSelector* selector)
+{
+ if (selector) {
+ ASSERT(m_floatingSelectors.contains(selector));
+ m_floatingSelectors.remove(selector);
+ }
+ return selector;
+}
+
+CSSParserValueList* CSSParser::createFloatingValueList()
+{
+ CSSParserValueList* list = new CSSParserValueList;
+ m_floatingValueLists.add(list);
+ return list;
+}
+
+CSSParserValueList* CSSParser::sinkFloatingValueList(CSSParserValueList* list)
+{
+ if (list) {
+ ASSERT(m_floatingValueLists.contains(list));
+ m_floatingValueLists.remove(list);
+ }
+ return list;
+}
+
+CSSParserFunction* CSSParser::createFloatingFunction()
+{
+ CSSParserFunction* function = new CSSParserFunction;
+ m_floatingFunctions.add(function);
+ return function;
+}
+
+CSSParserFunction* CSSParser::sinkFloatingFunction(CSSParserFunction* function)
+{
+ if (function) {
+ ASSERT(m_floatingFunctions.contains(function));
+ m_floatingFunctions.remove(function);
+ }
+ return function;
+}
+
+CSSParserValue& CSSParser::sinkFloatingValue(CSSParserValue& value)
+{
+ if (value.unit == CSSParserValue::Function) {
+ ASSERT(m_floatingFunctions.contains(value.function));
+ m_floatingFunctions.remove(value.function);
+ }
+ return value;
+}
+
+MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
+{
+ delete m_floatingMediaQueryExp;
+ m_floatingMediaQueryExp = new MediaQueryExp(mediaFeature, values);
+ return m_floatingMediaQueryExp;
+}
+
+MediaQueryExp* CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* e)
+{
+ ASSERT(e == m_floatingMediaQueryExp);
+ m_floatingMediaQueryExp = 0;
+ return e;
+}
+
+Vector<MediaQueryExp*>* CSSParser::createFloatingMediaQueryExpList()
+{
+ if (m_floatingMediaQueryExpList) {
+ deleteAllValues(*m_floatingMediaQueryExpList);
+ delete m_floatingMediaQueryExpList;
+ }
+ m_floatingMediaQueryExpList = new Vector<MediaQueryExp*>;
+ return m_floatingMediaQueryExpList;
+}
+
+Vector<MediaQueryExp*>* CSSParser::sinkFloatingMediaQueryExpList(Vector<MediaQueryExp*>* l)
+{
+ ASSERT(l == m_floatingMediaQueryExpList);
+ m_floatingMediaQueryExpList = 0;
+ return l;
+}
+
+MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor r, const String& mediaType, Vector<MediaQueryExp*>* exprs)
+{
+ delete m_floatingMediaQuery;
+ m_floatingMediaQuery = new MediaQuery(r, mediaType, exprs);
+ return m_floatingMediaQuery;
+}
+
+MediaQuery* CSSParser::createFloatingMediaQuery(Vector<MediaQueryExp*>* exprs)
+{
+ return createFloatingMediaQuery(MediaQuery::None, "all", exprs);
+}
+
+MediaQuery* CSSParser::sinkFloatingMediaQuery(MediaQuery* mq)
+{
+ ASSERT(mq == m_floatingMediaQuery);
+ m_floatingMediaQuery = 0;
+ return mq;
+}
+
+MediaList* CSSParser::createMediaList()
+{
+ RefPtr<MediaList> list = MediaList::create();
+ MediaList* result = list.get();
+ m_parsedStyleObjects.append(list.release());
+ return result;
+}
+
+CSSRule* CSSParser::createCharsetRule(const CSSParserString& charset)
+{
+ if (!m_styleSheet)
+ return 0;
+ RefPtr<CSSCharsetRule> rule = CSSCharsetRule::create(m_styleSheet, charset);
+ CSSCharsetRule* result = rule.get();
+ m_parsedStyleObjects.append(rule.release());
+ return result;
+}
+
+CSSRule* CSSParser::createImportRule(const CSSParserString& url, MediaList* media)
+{
+ if (!media || !m_styleSheet || !m_allowImportRules)
+ return 0;
+ RefPtr<CSSImportRule> rule = CSSImportRule::create(m_styleSheet, url, media);
+ CSSImportRule* result = rule.get();
+ m_parsedStyleObjects.append(rule.release());
+ return result;
+}
+
+CSSRule* CSSParser::createMediaRule(MediaList* media, CSSRuleList* rules)
+{
+ if (!media || !rules || !m_styleSheet)
+ return 0;
+ m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false;
+ RefPtr<CSSMediaRule> rule = CSSMediaRule::create(m_styleSheet, media, rules);
+ CSSMediaRule* result = rule.get();
+ m_parsedStyleObjects.append(rule.release());
+ return result;
+}
+
+CSSRuleList* CSSParser::createRuleList()
+{
+ RefPtr<CSSRuleList> list = CSSRuleList::create();
+ CSSRuleList* listPtr = list.get();
+
+ m_parsedRuleLists.append(list.release());
+ return listPtr;
+}
+
+WebKitCSSKeyframesRule* CSSParser::createKeyframesRule()
+{
+ m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false;
+ RefPtr<WebKitCSSKeyframesRule> rule = WebKitCSSKeyframesRule::create(m_styleSheet);
+ WebKitCSSKeyframesRule* rulePtr = rule.get();
+ m_parsedStyleObjects.append(rule.release());
+ return rulePtr;
+}
+
+CSSRule* CSSParser::createStyleRule(Vector<CSSSelector*>* selectors)
+{
+ m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false;
+ CSSStyleRule* result = 0;
+ markRuleBodyEnd();
+ if (selectors) {
+ RefPtr<CSSStyleRule> rule = CSSStyleRule::create(m_styleSheet, m_lastSelectorLineNumber);
+ rule->adoptSelectorVector(*selectors);
+ if (m_hasFontFaceOnlyValues)
+ deleteFontFaceOnlyValues();
+ rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties));
+ result = rule.get();
+ m_parsedStyleObjects.append(rule.release());
+ if (m_ruleRanges)
+ m_ruleRanges->set(result, std::pair<unsigned, unsigned>(m_ruleBodyStartOffset, m_ruleBodyEndOffset));
+ }
+ resetRuleBodyMarks();
+ clearProperties();
+ return result;
+}
+
+CSSRule* CSSParser::createFontFaceRule()
+{
+ m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false;
+ RefPtr<CSSFontFaceRule> rule = CSSFontFaceRule::create(m_styleSheet);
+ for (unsigned i = 0; i < m_numParsedProperties; ++i) {
+ CSSProperty* property = m_parsedProperties[i];
+ int id = property->id();
+ if ((id == CSSPropertyFontWeight || id == CSSPropertyFontStyle || id == CSSPropertyFontVariant) && property->value()->isPrimitiveValue()) {
+ RefPtr<CSSValue> value = property->m_value.release();
+ property->m_value = CSSValueList::createCommaSeparated();
+ static_cast<CSSValueList*>(property->m_value.get())->append(value.release());
+ }
+ }
+ rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties));
+ clearProperties();
+ CSSFontFaceRule* result = rule.get();
+ m_parsedStyleObjects.append(rule.release());
+ return result;
+}
+
+void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
+{
+ if (!m_styleSheet || !m_allowNamespaceDeclarations)
+ return;
+ m_allowImportRules = false;
+ m_allowVariablesRules = false;
+ m_styleSheet->addNamespace(this, prefix, uri);
+}
+
+#if !ENABLE(CSS_VARIABLES)
+
+CSSRule* CSSParser::createVariablesRule(MediaList*, bool)
+{
+ return 0;
+}
+
+bool CSSParser::addVariable(const CSSParserString&, CSSParserValueList*)
+{
+ return false;
+}
+
+bool CSSParser::addVariableDeclarationBlock(const CSSParserString&)
+{
+ return false;
+}
+
+#else
+
+CSSRule* CSSParser::createVariablesRule(MediaList* mediaList, bool variablesKeyword)
+{
+ if (!m_allowVariablesRules)
+ return 0;
+ m_allowImportRules = false;
+ RefPtr<CSSVariablesRule> rule = CSSVariablesRule::create(m_styleSheet, mediaList, variablesKeyword);
+ rule->setDeclaration(CSSVariablesDeclaration::create(rule.get(), m_variableNames, m_variableValues));
+ clearVariables();
+ CSSRule* result = rule.get();
+ m_parsedStyleObjects.append(rule.release());
+ return result;
+}
+
+bool CSSParser::addVariable(const CSSParserString& name, CSSParserValueList* valueList)
+{
+ if (checkForVariables(valueList)) {
+ delete valueList;
+ return false;
+ }
+ m_variableNames.append(String(name));
+ m_variableValues.append(CSSValueList::createFromParserValueList(valueList));
+ return true;
+}
+
+bool CSSParser::addVariableDeclarationBlock(const CSSParserString&)
+{
+// FIXME: Disabling declarations as variable values for now since they no longer have a common base class with CSSValues.
+#if 0
+ m_variableNames.append(String(name));
+ m_variableValues.append(CSSMutableStyleDeclaration::create(0, m_parsedProperties, m_numParsedProperties));
+ clearProperties();
+#endif
+ return true;
+}
+
+#endif
+
+CSSRule* CSSParser::createPageRule(CSSSelector* pageSelector)
+{
+ // FIXME: Margin at-rules are ignored.
+ m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false;
+ CSSPageRule* pageRule = 0;
+ if (pageSelector) {
+ RefPtr<CSSPageRule> rule = CSSPageRule::create(m_styleSheet, pageSelector, m_lastSelectorLineNumber);
+ rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties));
+ pageRule = rule.get();
+ m_parsedStyleObjects.append(rule.release());
+ }
+ clearProperties();
+ return pageRule;
+}
+
+CSSRule* CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
+{
+ // FIXME: Implement margin at-rule here, using:
+ // - marginBox: margin box
+ // - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_numParsedProperties) are for this at-rule.
+ // 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.
+
+ endDeclarationsForMarginBox();
+ return 0; // until this method is implemented.
+}
+
+void CSSParser::startDeclarationsForMarginBox()
+{
+ m_numParsedPropertiesBeforeMarginBox = m_numParsedProperties;
+}
+
+void CSSParser::endDeclarationsForMarginBox()
+{
+ ASSERT(m_numParsedPropertiesBeforeMarginBox != INVALID_NUM_PARSED_PROPERTIES);
+ rollbackLastProperties(m_numParsedProperties - m_numParsedPropertiesBeforeMarginBox);
+ m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
+}
+
+void CSSParser::clearVariables()
+{
+ m_variableNames.clear();
+ m_variableValues.clear();
+}
+
+bool CSSParser::parseVariable(CSSVariablesDeclaration* declaration, const String& variableName, const String& variableValue)
+{
+ m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
+
+ String nameValuePair = variableName + ": ";
+ nameValuePair += variableValue;
+
+ setupParser("@-webkit-variables-decls{", nameValuePair, "} ");
+ cssyyparse(this);
+ m_rule = 0;
+
+ bool ok = false;
+ if (m_variableNames.size()) {
+ ok = true;
+ declaration->addParsedVariable(variableName, m_variableValues[0]);
+ }
+
+ clearVariables();
+
+ return ok;
+}
+
+void CSSParser::parsePropertyWithResolvedVariables(int propId, bool isImportant, CSSMutableStyleDeclaration* declaration, CSSParserValueList* list)
+{
+ m_valueList = list;
+ m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
+
+ if (parseValue(propId, isImportant))
+ declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
+
+ clearProperties();
+ m_valueList = 0;
+}
+
+bool CSSParser::checkForVariables(CSSParserValueList* valueList)
+{
+ if (!valueList || !valueList->containsVariables())
+ return false;
+
+ bool hasVariables = false;
+ for (unsigned i = 0; i < valueList->size(); ++i) {
+ if (valueList->valueAt(i)->isVariable()) {
+ hasVariables = true;
+ break;
+ }
+
+ if (valueList->valueAt(i)->unit == CSSParserValue::Function && checkForVariables(valueList->valueAt(i)->function->args)) {
+ hasVariables = true;
+ break;
+ }
+ }
+
+ return hasVariables;
+}
+
+void CSSParser::addUnresolvedProperty(int propId, bool important)
+{
+ RefPtr<CSSVariableDependentValue> val = CSSVariableDependentValue::create(CSSValueList::createFromParserValueList(m_valueList));
+ addProperty(propId, val.release(), important);
+}
+
+void CSSParser::deleteFontFaceOnlyValues()
+{
+ ASSERT(m_hasFontFaceOnlyValues);
+ int deletedProperties = 0;
+
+ for (unsigned i = 0; i < m_numParsedProperties; ++i) {
+ CSSProperty* property = m_parsedProperties[i];
+ int id = property->id();
+ if ((id == CSSPropertyFontWeight || id == CSSPropertyFontStyle || id == CSSPropertyFontVariant) && property->value()->isValueList()) {
+ delete property;
+ deletedProperties++;
+ } else if (deletedProperties)
+ m_parsedProperties[i - deletedProperties] = m_parsedProperties[i];
+ }
+
+ m_numParsedProperties -= deletedProperties;
+}
+
+WebKitCSSKeyframeRule* CSSParser::createKeyframeRule(CSSParserValueList* keys)
+{
+ // Create a key string from the passed keys
+ String keyString;
+ for (unsigned i = 0; i < keys->size(); ++i) {
+ float key = (float) keys->valueAt(i)->fValue;
+ if (i != 0)
+ keyString += ",";
+ keyString += String::number(key);
+ keyString += "%";
+ }
+
+ RefPtr<WebKitCSSKeyframeRule> keyframe = WebKitCSSKeyframeRule::create(m_styleSheet);
+ keyframe->setKeyText(keyString);
+ keyframe->setDeclaration(CSSMutableStyleDeclaration::create(0, m_parsedProperties, m_numParsedProperties));
+
+ clearProperties();
+
+ WebKitCSSKeyframeRule* keyframePtr = keyframe.get();
+ m_parsedStyleObjects.append(keyframe.release());
+ return keyframePtr;
+}
+
+void CSSParser::invalidBlockHit()
+{
+ if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
+ m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
+}
+
+void CSSParser::updateLastSelectorLineAndPosition()
+{
+ m_lastSelectorLineNumber = m_lineNumber;
+ markRuleBodyStart();
+}
+
+void CSSParser::markRuleBodyStart()
+{
+ unsigned offset = yytext - m_data;
+ if (!m_ruleBodyStartOffset || offset < m_ruleBodyStartOffset)
+ m_ruleBodyStartOffset = offset;
+}
+
+void CSSParser::markRuleBodyEnd()
+{
+ unsigned offset = yytext - m_data;
+ if (offset > m_ruleBodyEndOffset)
+ m_ruleBodyEndOffset = offset;
+}
+
+static int cssPropertyID(const UChar* propertyName, unsigned length)
+{
+ if (!length)
+ return 0;
+ if (length > maxCSSPropertyNameLength)
+ return 0;
+
+ char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
+
+ for (unsigned i = 0; i != length; ++i) {
+ UChar c = propertyName[i];
+ if (c == 0 || c >= 0x7F)
+ return 0; // illegal character
+ buffer[i] = toASCIILower(c);
+ }
+ buffer[length] = '\0';
+
+ const char* name = buffer;
+ if (buffer[0] == '-') {
+ if (!strcmp(buffer, "-apple-dashboard-region") || !strcmp(buffer, "-apple-line-clamp")) {
+ // Support two Apple-specific CSS properties previously used for
+ // the Dashboard and Safari RSS line clamping.
+ memmove(buffer + 7, buffer + 6, length + 1 - 6);
+ memcpy(buffer, "-webkit", 7);
+ ++length;
+ } else if (!strcmp(buffer, "-webkit-opacity")) {
+ // Honor -webkit-opacity as a synonym for opacity. This was the only
+ // syntax that worked in Safari 1.1, and may be in use on some websites and widgets.
+ const char* const opacity = "opacity";
+ name = opacity;
+ length = 7;
+ } else if (hasPrefix(buffer, length, "-webkit-border-")) {
+ // -webkit-border-*-*-radius worked in Safari 4 and earlier. -webkit-border-radius syntax
+ // differs from border-radius, so it remains as a distinct property.
+ if (!strcmp(buffer + 15, "top-left-radius")
+ || !strcmp(buffer + 15, "top-right-radius")
+ || !strcmp(buffer + 15, "bottom-right-radius")
+ || !strcmp(buffer + 15, "bottom-left-radius")) {
+ name = buffer + 8;
+ length -= 8;
+ }
+ }
+ }
+
+ const Property* hashTableEntry = findProperty(name, length);
+ return hashTableEntry ? hashTableEntry->id : 0;
+}
+
+int cssPropertyID(const String& string)
+{
+ return cssPropertyID(string.characters(), string.length());
+}
+
+int cssPropertyID(const CSSParserString& string)
+{
+ return cssPropertyID(string.characters, string.length);
+}
+
+int cssValueKeywordID(const CSSParserString& string)
+{
+ unsigned length = string.length;
+ if (!length)
+ return 0;
+ if (length > maxCSSValueKeywordLength)
+ return 0;
+
+ char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
+
+ for (unsigned i = 0; i != length; ++i) {
+ UChar c = string.characters[i];
+ if (c == 0 || c >= 0x7F)
+ return 0; // illegal character
+ buffer[i] = WTF::toASCIILower(c);
+ }
+ buffer[length] = '\0';
+
+ if (buffer[0] == '-') {
+ // If the prefix is -apple- or -khtml-, change it to -webkit-.
+ // This makes the string one character longer.
+ if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
+ memmove(buffer + 7, buffer + 6, length + 1 - 6);
+ memcpy(buffer, "-webkit", 7);
+ ++length;
+ }
+ }
+
+ const Value* hashTableEntry = findValue(buffer, length);
+ return hashTableEntry ? hashTableEntry->id : 0;
+}
+
+// "ident" from the CSS tokenizer, minus backslash-escape sequences
+static bool isCSSTokenizerIdentifier(const String& string)
+{
+ const UChar* p = string.characters();
+ const UChar* end = p + string.length();
+
+ // -?
+ if (p != end && p[0] == '-')
+ ++p;
+
+ // {nmstart}
+ if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p[0])))
+ return false;
+ ++p;
+
+ // {nmchar}*
+ for (; p != end; ++p) {
+ if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p[0])))
+ return false;
+ }
+
+ return true;
+}
+
+// "url" from the CSS tokenizer, minus backslash-escape sequences
+static bool isCSSTokenizerURL(const String& string)
+{
+ const UChar* p = string.characters();
+ const UChar* end = p + string.length();
+
+ for (; p != end; ++p) {
+ UChar c = p[0];
+ switch (c) {
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ break;
+ default:
+ if (c < '*')
+ return false;
+ if (c <= '~')
+ break;
+ if (c < 128)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// We use single quotes for now because markup.cpp uses double quotes.
+String quoteCSSString(const String& string)
+{
+ // For efficiency, we first pre-calculate the length of the quoted string, then we build the actual one.
+ // Please see below for the actual logic.
+ unsigned quotedStringSize = 2; // Two quotes surrounding the entire string.
+ bool afterEscape = false;
+ for (unsigned i = 0; i < string.length(); ++i) {
+ UChar ch = string[i];
+ if (ch == '\\' || ch == '\'') {
+ quotedStringSize += 2;
+ afterEscape = false;
+ } else if (ch < 0x20 || ch == 0x7F) {
+ quotedStringSize += 2 + (ch >= 0x10);
+ afterEscape = true;
+ } else {
+ quotedStringSize += 1 + (afterEscape && (isASCIIHexDigit(ch) || ch == ' '));
+ afterEscape = false;
+ }
+ }
+
+ StringBuffer buffer(quotedStringSize);
+ unsigned index = 0;
+ buffer[index++] = '\'';
+ afterEscape = false;
+ for (unsigned i = 0; i < string.length(); ++i) {
+ UChar ch = string[i];
+ if (ch == '\\' || ch == '\'') {
+ buffer[index++] = '\\';
+ buffer[index++] = ch;
+ afterEscape = false;
+ } else if (ch < 0x20 || ch == 0x7F) { // Control characters.
+ static const char hexDigits[17] = "0123456789abcdef";
+ buffer[index++] = '\\';
+ if (ch >= 0x10)
+ buffer[index++] = hexDigits[ch >> 4];
+ buffer[index++] = hexDigits[ch & 0xF];
+ afterEscape = true;
+ } else {
+ // Space character may be required to separate backslash-escape sequence and normal characters.
+ if (afterEscape && (isASCIIHexDigit(ch) || ch == ' '))
+ buffer[index++] = ' ';
+ buffer[index++] = ch;
+ afterEscape = false;
+ }
+ }
+ buffer[index++] = '\'';
+
+ ASSERT(quotedStringSize == index);
+ return String::adopt(buffer);
+}
+
+String quoteCSSStringIfNeeded(const String& string)
+{
+ return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string);
+}
+
+String quoteCSSURLIfNeeded(const String& string)
+{
+ return isCSSTokenizerURL(string) ? string : quoteCSSString(string);
+}
+
+#define YY_DECL int CSSParser::lex()
+#define yyconst const
+typedef int yy_state_type;
+typedef unsigned YY_CHAR;
+// The following line makes sure we treat non-Latin-1 Unicode characters correctly.
+#define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
+#define YY_DO_BEFORE_ACTION \
+ yytext = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = 0; \
+ yy_c_buf_p = yy_cp;
+#define YY_BREAK break;
+#define ECHO
+#define YY_RULE_SETUP
+#define INITIAL 0
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+#define yyterminate() yyTok = END_TOKEN; return yyTok
+#define YY_FATAL_ERROR(a)
+// The following line is needed to build the tokenizer with a condition stack.
+// The macro is used in the tokenizer grammar with lines containing
+// BEGIN(mediaqueries) and BEGIN(initial). yy_start acts as index to
+// tokenizer transition table, and 'mediaqueries' and 'initial' are
+// offset multipliers that specify which transitions are active
+// in the tokenizer during in each condition (tokenizer state).
+#define BEGIN yy_start = 1 + 2 *
+
+#include "tokenizer.cpp"
+
+}