HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Froyo
|
2.2_r1
下载
查看原文件
收藏
根目录
external
webkit
WebCore
css
CSSParser.cpp
/* * 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 Apple Inc. All rights reserved. * Copyright (C) 2007 Nicholas Shanks
* Copyright (C) 2008 Eric Seidel
* 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 "CString.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 "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 "WebKitCSSKeyframeRule.h" #include "WebKitCSSKeyframesRule.h" #include "WebKitCSSTransformValue.h" #include
#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.c" #ifdef ANDROID_INSTRUMENT #include "TimeCounter.h" #endif namespace WebCore { 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
(fastMalloc(32 * sizeof(CSSProperty*)))) , m_numParsedProperties(0) , m_maxParsedProperties(32) , m_inParseShorthand(0) , m_currentShorthand(0) , m_implicitShorthand(false) , m_hasFontFaceOnlyValues(false) , m_hadSyntacticallyValidCSSRule(false) , m_defaultNamespace(starAtom) , m_data(0) , yy_start(1) , 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
(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; } void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string) { #ifdef ANDROID_INSTRUMENT android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); #endif m_styleSheet = sheet; m_defaultNamespace = starAtom; // Reset the default namespace. setupParser("", string, ""); cssyyparse(this); m_rule = 0; #ifdef ANDROID_INSTRUMENT android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); #endif } PassRefPtr
CSSParser::parseRule(CSSStyleSheet* sheet, const String& string) { #ifdef ANDROID_INSTRUMENT android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); #endif m_styleSheet = sheet; m_allowNamespaceDeclarations = false; setupParser("@-webkit-rule{", string, "} "); cssyyparse(this); #ifdef ANDROID_INSTRUMENT android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); #endif return m_rule.release(); } PassRefPtr
CSSParser::parseKeyframeRule(CSSStyleSheet *sheet, const String &string) { #ifdef ANDROID_INSTRUMENT android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); #endif m_styleSheet = sheet; setupParser("@-webkit-keyframe-rule{ ", string, "} "); cssyyparse(this); #ifdef ANDROID_INSTRUMENT android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); #endif return m_keyframe.release(); } bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int id, const String& string, bool important) { #ifdef ANDROID_INSTRUMENT android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); #endif ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet()); m_styleSheet = static_cast
(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(); } #ifdef ANDROID_INSTRUMENT android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); #endif 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) { color = 0; CSSParser parser(true); // First try creating a color specified by name or the "#" syntax. if (!parser.parseColor(string, color, strict)) { RefPtr
dummyStyleDeclaration = CSSMutableStyleDeclaration::create(); // Now try to create a color from the rgb() or rgba() syntax. if (parser.parseColor(dummyStyleDeclaration.get(), string)) { CSSValue* value = parser.m_parsedProperties[0]->value(); if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) { CSSPrimitiveValue* primitiveValue = static_cast
(value); color = primitiveValue->getRGBA32Value(); } } else return false; } return true; } bool CSSParser::parseColor(CSSMutableStyleDeclaration* declaration, const String& string) { #ifdef ANDROID_INSTRUMENT android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); #endif ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet()); m_styleSheet = static_cast
(declaration->stylesheet()); setupParser("@-webkit-decls{color:", string, "} "); cssyyparse(this); m_rule = 0; #ifdef ANDROID_INSTRUMENT android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); #endif return (m_numParsedProperties && m_parsedProperties[0]->m_id == CSSPropertyColor); } void CSSParser::parseSelector(const String& string, Document* doc, CSSSelectorList& selectorList) { #ifdef ANDROID_INSTRUMENT android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); #endif RefPtr
dummyStyleSheet = CSSStyleSheet::create(doc); m_styleSheet = dummyStyleSheet.get(); m_selectorListForParseSelector = &selectorList; setupParser("@-webkit-selector{", string, "}"); cssyyparse(this); m_selectorListForParseSelector = 0; #ifdef ANDROID_INSTRUMENT android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); #endif } bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration* declaration, const String& string) { #ifdef ANDROID_INSTRUMENT android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); #endif ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet()); m_styleSheet = static_cast
(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(); } #ifdef ANDROID_INSTRUMENT android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); #endif return ok; } bool CSSParser::parseMediaQuery(MediaList* queries, const String& string) { if (string.isEmpty()) return true; #ifdef ANDROID_INSTRUMENT android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); #endif 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; } #ifdef ANDROID_INSTRUMENT android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); #endif return ok; } void CSSParser::addProperty(int propId, PassRefPtr
value, bool important) { auto_ptr
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
(fastRealloc(m_parsedProperties, m_maxParsedProperties * sizeof(CSSProperty*))); } m_parsedProperties[m_numParsedProperties++] = prop.release(); } void CSSParser::rollbackLastProperties(int num) { ASSERT(num >= 0); ASSERT(m_numParsedProperties >= static_cast
(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_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
(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
parsedValue; switch (static_cast
(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: //
{1,2} | auto | portrait | landscape | inherit case CSSPropertyQuotes: // [
]+ | 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: // [
|
|
| 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: //
| 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 |
| inherit if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitCenter) || id == CSSValueStart || id == CSSValueEnd || value->unit == CSSPrimitiveValue::CSS_STRING) validPrimitive = true; break; case CSSPropertyOutlineStyle: // (
except hidden) | auto | inherit if (id == CSSValueAuto || id == CSSValueNone || (id >= CSSValueInset && id <= CSSValueDouble)) validPrimitive = true; break; case CSSPropertyBorderTopStyle: ////
| inherit case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed | case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset case CSSPropertyBorderLeftStyle: 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: //
| invert | inherit // Outline color has "invert" as additional keyword. // Also, we want to allow the special focus color even in strict parsing mode. if (propId == CSSPropertyOutlineColor && (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor)) { validPrimitive = true; break; } /* nobreak */ case CSSPropertyBackgroundColor: //
| inherit case CSSPropertyBorderTopColor: //
| inherit case CSSPropertyBorderRightColor: //
| inherit case CSSPropertyBorderBottomColor: //
| inherit case CSSPropertyBorderLeftColor: //
| inherit case CSSPropertyColor: //
| 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: { // [
,]* [ 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-in | -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit RefPtr
list; while (value && value->unit == CSSPrimitiveValue::CSS_URI) { if (!list) list = CSSValueList::createCommaSeparated(); String uri = value->string; Vector
coords; value = m_valueList->next(); while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) { coords.append(int(value->fValue)); value = m_valueList->next(); } IntPoint hotspot; 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
val1; RefPtr
val2; int propId1, propId2; bool result = false; if (parseFillProperty(propId, propId1, propId2, val1, val2)) { OwnPtr
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: //
| 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: //
| inherit case CSSPropertyBorderTopWidth: ////
| inherit case CSSPropertyBorderRightWidth: // Which is defined as case CSSPropertyBorderBottomWidth: // thin | medium | thick |
case CSSPropertyBorderLeftWidth: case CSSPropertyWebkitColumnRuleWidth: if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick) validPrimitive = true; else validPrimitive = validUnit(value, FLength, m_strict); break; case CSSPropertyLetterSpacing: // normal |
| inherit case CSSPropertyWordSpacing: // normal |
| 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: //
|
| inherit case CSSPropertyPaddingTop: ////
| inherit case CSSPropertyPaddingRight: // Which is defined as case CSSPropertyPaddingBottom: //
|
case CSSPropertyPaddingLeft: //// case CSSPropertyWebkitPaddingStart: validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict)); break; case CSSPropertyMaxHeight: //
|
| none | inherit case CSSPropertyMaxWidth: //
|
| none | inherit if (id == CSSValueNone || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) { validPrimitive = true; break; } /* nobreak */ case CSSPropertyMinHeight: //
|
| inherit case CSSPropertyMinWidth: //
|
| inherit if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) validPrimitive = true; else validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict)); break; case CSSPropertyFontSize: //
|
|
|
| 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 | //
|
| inherit if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle) validPrimitive = true; else validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict)); break; case CSSPropertyHeight: //
|
| auto | inherit case CSSPropertyWidth: //
|
| 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: //
|
| auto | inherit case CSSPropertyLeft: //
|
| auto | inherit case CSSPropertyRight: //
|
| auto | inherit case CSSPropertyTop: //
|
| auto | inherit case CSSPropertyMarginTop: ////
| inherit case CSSPropertyMarginRight: // Which is defined as case CSSPropertyMarginBottom: //
|
| auto | inherit case CSSPropertyMarginLeft: //// case CSSPropertyWebkitMarginStart: if (id == CSSValueAuto) validPrimitive = true; else validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict)); break; case CSSPropertyZIndex: // auto |
| inherit if (id == CSSValueAuto) { validPrimitive = true; break; } /* nobreak */ case CSSPropertyOrphans: //
| inherit case CSSPropertyWidows: //
| inherit // ### not supported later on validPrimitive = (!id && validUnit(value, FInteger, false)); break; case CSSPropertyLineHeight: // normal |
|
|
| inherit if (id == CSSValueNormal) validPrimitive = true; else validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict)); break; case CSSPropertyCounterIncrement: // [
? ]+ | none | inherit if (id != CSSValueNone) return parseCounter(propId, 1, important); validPrimitive = true; break; case CSSPropertyCounterReset: // [
? ]+ | none | inherit if (id != CSSValueNone) return parseCounter(propId, 0, important); validPrimitive = true; break; case CSSPropertyFontFamily: // [[
|
],]* [
|
] | inherit { parsedValue = parseFontFamily(); break; } case CSSPropertyTextDecoration: case CSSPropertyWebkitTextDecorationsInEffect: // none | [ underline || overline || line-through || blink ] | inherit if (id == CSSValueNone) { validPrimitive = true; } else { RefPtr
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 |
|
| 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
values = CSSValueList::createCommaSeparated(); CSSParserValue* val; RefPtr
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
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
parsedValue1 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); RefPtr
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::create(parsedValue1.release(), parsedValue2.release()); RefPtr
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
val = parseTransform(); if (val) { addProperty(propId, val, important); return true; } return false; } break; case CSSPropertyWebkitTransformOrigin: case CSSPropertyWebkitTransformOriginX: case CSSPropertyWebkitTransformOriginY: case CSSPropertyWebkitTransformOriginZ: { RefPtr
val1; RefPtr
val2; RefPtr
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
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
val1; RefPtr
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 CSSPropertyWebkitAnimationName: case CSSPropertyWebkitAnimationPlayState: case CSSPropertyWebkitAnimationIterationCount: case CSSPropertyWebkitAnimationTimingFunction: case CSSPropertyWebkitTransitionDelay: case CSSPropertyWebkitTransitionDuration: case CSSPropertyWebkitTransitionTimingFunction: case CSSPropertyWebkitTransitionProperty: { RefPtr
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 |
if (id == CSSValueNormal) validPrimitive = true; else validPrimitive = validUnit(value, FLength | FNonNeg, m_strict); break; case CSSPropertyWebkitColumnWidth: // auto |
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: //
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 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: //
|
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' ||
] | inherit { const int properties[3] = { CSSPropertyBorderWidth, CSSPropertyBorderStyle, CSSPropertyBorderColor }; return parseShorthand(propId, properties, 3, important); } case CSSPropertyBorderTop: // [ 'border-top-width' || 'border-style' ||
] | inherit { const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle, CSSPropertyBorderTopColor}; return parseShorthand(propId, properties, 3, important); } case CSSPropertyBorderRight: // [ 'border-right-width' || 'border-style' ||
] | inherit { const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle, CSSPropertyBorderRightColor }; return parseShorthand(propId, properties, 3, important); } case CSSPropertyBorderBottom: // [ 'border-bottom-width' || 'border-style' ||
] | inherit { const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle, CSSPropertyBorderBottomColor }; return parseShorthand(propId, properties, 3, important); } case CSSPropertyBorderLeft: // [ 'border-left-width' || 'border-style' ||
] | inherit { const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle, CSSPropertyBorderLeftColor }; 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: //
{1,4} | inherit { const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor, CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor }; return parse4Values(propId, properties, important); } case CSSPropertyBorderWidth: //
{1,4} | inherit { const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth, CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth }; return parse4Values(propId, properties, important); } case CSSPropertyBorderStyle: //
{1,4} | inherit { const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle, CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle }; return parse4Values(propId, properties, important); } case CSSPropertyMargin: //
{1,4} | inherit { const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight, CSSPropertyMarginBottom, CSSPropertyMarginLeft }; return parse4Values(propId, properties, important); } case CSSPropertyPadding: //
{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 CSSPropertyFontStretch: case CSSPropertyPage: case CSSPropertyTextLineThrough: case CSSPropertyTextOverline: case CSSPropertyTextUnderline: case CSSPropertyWebkitVariableDeclarationBlock: return false; #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR case CSSPropertyWebkitTapHighlightColor: parsedValue = parseColor(); if (parsedValue) m_valueList->next(); 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; } void CSSParser::addFillValue(RefPtr
& lval, PassRefPtr
rval) { if (lval) { if (lval->isValueList()) static_cast
(lval.get())->append(rval); else { PassRefPtr
oldlVal(lval.release()); PassRefPtr
list = CSSValueList::createCommaSeparated(); list->append(oldlVal); list->append(rval); lval = list; } } else lval = rval; } static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr
& 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
values[cMaxFillProperties]; RefPtr
clipValue; RefPtr
positionYValue; RefPtr
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
val1; RefPtr
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
& lval, PassRefPtr
rval) { if (lval) { if (lval->isValueList()) static_cast
(lval.get())->append(rval); else { PassRefPtr
oldVal(lval.release()); PassRefPtr
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 }; const int numProperties = sizeof(properties) / sizeof(properties[0]); ShorthandScope scope(this, CSSPropertyWebkitAnimation); bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary RefPtr
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
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
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
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; } // [
|
|
| attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit // in CSS 2.1 this got somewhat reduced: // [
| attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit bool CSSParser::parseContent(int propId, bool important) { RefPtr
values = CSSValueList::createCommaSeparated(); while (CSSParserValue* val = m_valueList->current()) { RefPtr
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
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
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
& 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
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
& value1, RefPtr
& 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
& value1, RefPtr
& 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
(value1.get())->getIdent()); } } PassRefPtr
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
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
(propId); RefPtr
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
& retValue1, RefPtr
& retValue2) { RefPtr
values; RefPtr
values2; CSSParserValue* val; RefPtr
value; RefPtr
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
currValue; RefPtr
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
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
CSSParser::parseAnimationDirection() { CSSParserValue* value = m_valueList->current(); if (value->id == CSSValueNormal || value->id == CSSValueAlternate) return CSSPrimitiveValue::createIdentifier(value->id); return 0; } PassRefPtr
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
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
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
CSSParser::parseAnimationPlayState() { CSSParserValue* value = m_valueList->current(); if (value->id == CSSValueRunning || value->id == CSSValuePaused) return CSSPrimitiveValue::createIdentifier(value->id); return 0; } PassRefPtr
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
& value1, RefPtr
& value2, RefPtr
& 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
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
& result) { RefPtr
values; CSSParserValue* val; RefPtr
value; bool allowComma = false; result = 0; while ((val = m_valueList->current())) { RefPtr
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 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
firstRegion = DashboardRegion::create(); DashboardRegion* region = 0; while (value) { if (region == 0) { region = firstRegion.get(); } else { RefPtr
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
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
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
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
identifier = CSSPrimitiveValue::create(i->string, CSSPrimitiveValue::CSS_STRING); RefPtr
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
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::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
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
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 //
|
|
|
| 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
CSSParser::parseFontFamily() { RefPtr
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
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
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
values; if (m_valueList->size() > 1) values = CSSValueList::createCommaSeparated(); CSSParserValue* val; bool expectComma = false; while ((val = m_valueList->current())) { RefPtr
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
values; if (m_valueList->size() > 1) values = CSSValueList::createCommaSeparated(); CSSParserValue* val; bool expectComma = false; while ((val = m_valueList->current())) { RefPtr
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
values; if (m_valueList->size() > 1) values = CSSValueList::createCommaSeparated(); CSSParserValue* val; bool expectComma = false; while ((val = m_valueList->current())) { RefPtr
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
(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
values(CSSValueList::createCommaSeparated()); CSSParserValue* val; bool expectComma = false; bool allowFormat = false; bool failed = false; RefPtr
uriValue; while ((val = m_valueList->current())) { RefPtr
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
values = CSSValueList::createCommaSeparated(); CSSParserValue* currentValue; bool failed = false; while ((currentValue = m_valueList->current())) { 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; } values->append(CSSUnicodeRangeValue::create(from, to)); m_valueList->next(); } if (failed || !values->length()) return false; addProperty(CSSPropertyUnicodeRange, values.release(), m_important); return true; } bool CSSParser::parseColor(const String &name, RGBA32& rgb, bool strict) { if (!strict && Color::parseHexColor(name, rgb)) return true; // try a little harder Color tc; tc.setNamedColor(name); if (tc.isValid()) { rgb = tc.rgb(); return true; } return false; } 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] = static_cast
(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.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, unitType, true)) return false; colorArray[i] = static_cast
(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 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] = static_cast
(max(0.0, min(1.0, v->fValue)) * 255); } return true; } // The CSS3 specification defines the format of a HSL color as // hsl(
,
,
) // and with alpha, the format is // hsla(
,
,
,
) // 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
(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
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, bool svg) { 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 (!svg) { 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; } 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
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
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
values; RefPtr
x; RefPtr
y; RefPtr
blur; RefPtr
spread; RefPtr
style; RefPtr
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
(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
(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
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 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
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
(val->unit)); } // Now for the mask. RefPtr
mask; val = m_valueList->next(); if (val) { if (!parseBorderImage(propId, important, mask)) return false; } RefPtr