Home | History | Annotate | Download | only in css
      1 /*
      2  * Copyright (C) 2003 Lars Knoll (knoll (at) kde.org)
      3  * Copyright (C) 2005 Allan Sandfeld Jensen (kde (at) carewolf.com)
      4  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
      5  * Copyright (C) 2007 Nicholas Shanks <webkit (at) nickshanks.com>
      6  * Copyright (C) 2008 Eric Seidel <eric (at) webkit.org>
      7  * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
      8  *
      9  * This library is free software; you can redistribute it and/or
     10  * modify it under the terms of the GNU Library General Public
     11  * License as published by the Free Software Foundation; either
     12  * version 2 of the License, or (at your option) any later version.
     13  *
     14  * This library is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  * Library General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU Library General Public License
     20  * along with this library; see the file COPYING.LIB.  If not, write to
     21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     22  * Boston, MA 02110-1301, USA.
     23  */
     24 
     25 #include "config.h"
     26 #include "CSSParser.h"
     27 
     28 #include "CSSBorderImageValue.h"
     29 #include "CSSCanvasValue.h"
     30 #include "CSSCharsetRule.h"
     31 #include "CSSCursorImageValue.h"
     32 #include "CSSFontFaceRule.h"
     33 #include "CSSFontFaceSrcValue.h"
     34 #include "CSSGradientValue.h"
     35 #include "CSSImageValue.h"
     36 #include "CSSImportRule.h"
     37 #include "CSSInheritedValue.h"
     38 #include "CSSInitialValue.h"
     39 #include "CSSLineBoxContainValue.h"
     40 #include "CSSMediaRule.h"
     41 #include "CSSMutableStyleDeclaration.h"
     42 #include "CSSPageRule.h"
     43 #include "CSSPrimitiveValue.h"
     44 #include "CSSPrimitiveValueCache.h"
     45 #include "CSSProperty.h"
     46 #include "CSSPropertyNames.h"
     47 #include "CSSPropertySourceData.h"
     48 #include "CSSQuirkPrimitiveValue.h"
     49 #include "CSSReflectValue.h"
     50 #include "CSSRuleList.h"
     51 #include "CSSSelector.h"
     52 #include "CSSStyleRule.h"
     53 #include "CSSStyleSheet.h"
     54 #include "CSSTimingFunctionValue.h"
     55 #include "CSSUnicodeRangeValue.h"
     56 #include "CSSValueKeywords.h"
     57 #include "CSSValueList.h"
     58 #include "Counter.h"
     59 #include "Document.h"
     60 #include "FloatConversion.h"
     61 #include "FontFamilyValue.h"
     62 #include "FontValue.h"
     63 #include "HTMLParserIdioms.h"
     64 #include "HashTools.h"
     65 #include "MediaList.h"
     66 #include "MediaQueryExp.h"
     67 #include "Page.h"
     68 #include "Pair.h"
     69 #include "Rect.h"
     70 #include "RenderTheme.h"
     71 #include "ShadowValue.h"
     72 #include "WebKitCSSKeyframeRule.h"
     73 #include "WebKitCSSKeyframesRule.h"
     74 #include "WebKitCSSTransformValue.h"
     75 #include <limits.h>
     76 #include <wtf/HexNumber.h>
     77 #include <wtf/dtoa.h>
     78 #include <wtf/text/StringBuffer.h>
     79 
     80 #if ENABLE(DASHBOARD_SUPPORT)
     81 #include "DashboardRegion.h"
     82 #endif
     83 
     84 #define YYDEBUG 0
     85 
     86 #if YYDEBUG > 0
     87 extern int cssyydebug;
     88 #endif
     89 
     90 extern int cssyyparse(void* parser);
     91 
     92 using namespace std;
     93 using namespace WTF;
     94 
     95 #ifdef ANDROID_INSTRUMENT
     96 #include "TimeCounter.h"
     97 #endif
     98 
     99 namespace WebCore {
    100 
    101 static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
    102 static const double MAX_SCALE = 1000000;
    103 
    104 static bool equal(const CSSParserString& a, const char* b)
    105 {
    106     for (int i = 0; i < a.length; ++i) {
    107         if (!b[i])
    108             return false;
    109         if (a.characters[i] != b[i])
    110             return false;
    111     }
    112     return !b[a.length];
    113 }
    114 
    115 static bool equalIgnoringCase(const CSSParserString& a, const char* b)
    116 {
    117     for (int i = 0; i < a.length; ++i) {
    118         if (!b[i])
    119             return false;
    120         ASSERT(!isASCIIUpper(b[i]));
    121         if (toASCIILower(a.characters[i]) != b[i])
    122             return false;
    123     }
    124     return !b[a.length];
    125 }
    126 
    127 static bool hasPrefix(const char* string, unsigned length, const char* prefix)
    128 {
    129     for (unsigned i = 0; i < length; ++i) {
    130         if (!prefix[i])
    131             return true;
    132         if (string[i] != prefix[i])
    133             return false;
    134     }
    135     return false;
    136 }
    137 
    138 CSSParser::CSSParser(bool strictParsing)
    139     : m_strict(strictParsing)
    140     , m_important(false)
    141     , m_id(0)
    142     , m_styleSheet(0)
    143     , m_valueList(0)
    144     , m_parsedProperties(static_cast<CSSProperty**>(fastMalloc(32 * sizeof(CSSProperty*))))
    145     , m_numParsedProperties(0)
    146     , m_maxParsedProperties(32)
    147     , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
    148     , m_inParseShorthand(0)
    149     , m_currentShorthand(0)
    150     , m_implicitShorthand(false)
    151     , m_hasFontFaceOnlyValues(false)
    152     , m_hadSyntacticallyValidCSSRule(false)
    153     , m_defaultNamespace(starAtom)
    154     , m_inStyleRuleOrDeclaration(false)
    155     , m_selectorListRange(0, 0)
    156     , m_ruleBodyRange(0, 0)
    157     , m_propertyRange(UINT_MAX, UINT_MAX)
    158     , m_ruleRangeMap(0)
    159     , m_currentRuleData(0)
    160     , m_data(0)
    161     , yy_start(1)
    162     , m_lineNumber(0)
    163     , m_lastSelectorLineNumber(0)
    164     , m_allowImportRules(true)
    165     , m_allowNamespaceDeclarations(true)
    166 {
    167 #if YYDEBUG > 0
    168     cssyydebug = 1;
    169 #endif
    170     CSSPropertySourceData::init();
    171 }
    172 
    173 CSSParser::~CSSParser()
    174 {
    175     clearProperties();
    176     fastFree(m_parsedProperties);
    177 
    178     delete m_valueList;
    179 
    180     fastFree(m_data);
    181 
    182     fastDeleteAllValues(m_floatingSelectors);
    183     deleteAllValues(m_floatingSelectorVectors);
    184     deleteAllValues(m_floatingValueLists);
    185     deleteAllValues(m_floatingFunctions);
    186 }
    187 
    188 void CSSParserString::lower()
    189 {
    190     // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
    191     // that can potentially change the length of the string rather than the character
    192     // by character kind. If we don't need Unicode lowercasing, it would be good to
    193     // simplify this function.
    194 
    195     if (charactersAreAllASCII(characters, length)) {
    196         // Fast case for all-ASCII.
    197         for (int i = 0; i < length; i++)
    198             characters[i] = toASCIILower(characters[i]);
    199     } else {
    200         for (int i = 0; i < length; i++)
    201             characters[i] = Unicode::toLower(characters[i]);
    202     }
    203 }
    204 
    205 void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix)
    206 {
    207     int length = string.length() + strlen(prefix) + strlen(suffix) + 2;
    208 
    209     fastFree(m_data);
    210     m_data = static_cast<UChar*>(fastMalloc(length * sizeof(UChar)));
    211     for (unsigned i = 0; i < strlen(prefix); i++)
    212         m_data[i] = prefix[i];
    213 
    214     memcpy(m_data + strlen(prefix), string.characters(), string.length() * sizeof(UChar));
    215 
    216     unsigned start = strlen(prefix) + string.length();
    217     unsigned end = start + strlen(suffix);
    218     for (unsigned i = start; i < end; i++)
    219         m_data[i] = suffix[i - start];
    220 
    221     m_data[length - 1] = 0;
    222     m_data[length - 2] = 0;
    223 
    224     yy_hold_char = 0;
    225     yyleng = 0;
    226     yytext = yy_c_buf_p = m_data;
    227     yy_hold_char = *yy_c_buf_p;
    228     resetRuleBodyMarks();
    229 }
    230 
    231 void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string, int startLineNumber, StyleRuleRangeMap* ruleRangeMap)
    232 {
    233 #ifdef ANDROID_INSTRUMENT
    234     android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
    235 #endif
    236     setStyleSheet(sheet);
    237     m_defaultNamespace = starAtom; // Reset the default namespace.
    238     m_ruleRangeMap = ruleRangeMap;
    239     if (ruleRangeMap) {
    240         m_currentRuleData = CSSRuleSourceData::create();
    241         m_currentRuleData->styleSourceData = CSSStyleSourceData::create();
    242     }
    243 
    244     m_lineNumber = startLineNumber;
    245     setupParser("", string, "");
    246     cssyyparse(this);
    247     m_ruleRangeMap = 0;
    248     m_currentRuleData = 0;
    249     m_rule = 0;
    250 #ifdef ANDROID_INSTRUMENT
    251     android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
    252 #endif
    253 }
    254 
    255 PassRefPtr<CSSRule> CSSParser::parseRule(CSSStyleSheet* sheet, const String& string)
    256 {
    257 #ifdef ANDROID_INSTRUMENT
    258     android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
    259 #endif
    260     setStyleSheet(sheet);
    261     m_allowNamespaceDeclarations = false;
    262     setupParser("@-webkit-rule{", string, "} ");
    263     cssyyparse(this);
    264 #ifdef ANDROID_INSTRUMENT
    265     android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
    266 #endif
    267     return m_rule.release();
    268 }
    269 
    270 PassRefPtr<CSSRule> CSSParser::parseKeyframeRule(CSSStyleSheet *sheet, const String &string)
    271 {
    272 #ifdef ANDROID_INSTRUMENT
    273     android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
    274 #endif
    275     setStyleSheet(sheet);
    276     setupParser("@-webkit-keyframe-rule{ ", string, "} ");
    277     cssyyparse(this);
    278 #ifdef ANDROID_INSTRUMENT
    279     android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
    280 #endif
    281     return m_keyframe.release();
    282 }
    283 
    284 static inline bool isColorPropertyID(int propertyId)
    285 {
    286     switch (propertyId) {
    287     case CSSPropertyColor:
    288     case CSSPropertyBackgroundColor:
    289     case CSSPropertyBorderBottomColor:
    290     case CSSPropertyBorderLeftColor:
    291     case CSSPropertyBorderRightColor:
    292     case CSSPropertyBorderTopColor:
    293     case CSSPropertyOutlineColor:
    294     case CSSPropertyTextLineThroughColor:
    295     case CSSPropertyTextOverlineColor:
    296     case CSSPropertyTextUnderlineColor:
    297     case CSSPropertyWebkitBorderAfterColor:
    298     case CSSPropertyWebkitBorderBeforeColor:
    299     case CSSPropertyWebkitBorderEndColor:
    300     case CSSPropertyWebkitBorderStartColor:
    301     case CSSPropertyWebkitColumnRuleColor:
    302     case CSSPropertyWebkitTextEmphasisColor:
    303     case CSSPropertyWebkitTextFillColor:
    304     case CSSPropertyWebkitTextStrokeColor:
    305         return true;
    306     default:
    307         return false;
    308     }
    309 }
    310 
    311 static bool parseColorValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important, bool strict)
    312 {
    313     if (!string.length())
    314         return false;
    315     if (!isColorPropertyID(propertyId))
    316         return false;
    317     CSSParserString cssString;
    318     cssString.characters = const_cast<UChar*>(string.characters());
    319     cssString.length = string.length();
    320     int valueID = cssValueKeywordID(cssString);
    321     bool validPrimitive = false;
    322     if (valueID == CSSValueWebkitText)
    323         validPrimitive = true;
    324     else if (valueID == CSSValueCurrentcolor)
    325         validPrimitive = true;
    326     else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
    327              || (valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText && !strict)) {
    328         validPrimitive = true;
    329     }
    330 
    331     CSSStyleSheet* stylesheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
    332     if (!stylesheet || !stylesheet->document())
    333         return false;
    334     if (validPrimitive) {
    335         CSSProperty property(propertyId, stylesheet->document()->cssPrimitiveValueCache()->createIdentifierValue(valueID), important);
    336         declaration->addParsedProperty(property);
    337         return true;
    338     }
    339     RGBA32 color;
    340     if (!CSSParser::parseColor(string, color, strict && string[0] != '#'))
    341         return false;
    342     CSSProperty property(propertyId, stylesheet->document()->cssPrimitiveValueCache()->createColorValue(color), important);
    343     declaration->addParsedProperty(property);
    344     return true;
    345 }
    346 
    347 static inline bool isSimpleLengthPropertyID(int propertyId, bool& acceptsNegativeNumbers)
    348 {
    349     switch (propertyId) {
    350     case CSSPropertyFontSize:
    351     case CSSPropertyHeight:
    352     case CSSPropertyWidth:
    353     case CSSPropertyMinHeight:
    354     case CSSPropertyMinWidth:
    355     case CSSPropertyPaddingBottom:
    356     case CSSPropertyPaddingLeft:
    357     case CSSPropertyPaddingRight:
    358     case CSSPropertyPaddingTop:
    359     case CSSPropertyWebkitLogicalWidth:
    360     case CSSPropertyWebkitLogicalHeight:
    361     case CSSPropertyWebkitMinLogicalWidth:
    362     case CSSPropertyWebkitMinLogicalHeight:
    363     case CSSPropertyWebkitPaddingAfter:
    364     case CSSPropertyWebkitPaddingBefore:
    365     case CSSPropertyWebkitPaddingEnd:
    366     case CSSPropertyWebkitPaddingStart:
    367         acceptsNegativeNumbers = false;
    368         return true;
    369     case CSSPropertyBottom:
    370     case CSSPropertyLeft:
    371     case CSSPropertyMarginBottom:
    372     case CSSPropertyMarginLeft:
    373     case CSSPropertyMarginRight:
    374     case CSSPropertyMarginTop:
    375     case CSSPropertyRight:
    376     case CSSPropertyTextIndent:
    377     case CSSPropertyTop:
    378     case CSSPropertyWebkitMarginAfter:
    379     case CSSPropertyWebkitMarginBefore:
    380     case CSSPropertyWebkitMarginEnd:
    381     case CSSPropertyWebkitMarginStart:
    382         acceptsNegativeNumbers = true;
    383         return true;
    384     default:
    385         return false;
    386     }
    387 }
    388 
    389 static bool parseSimpleLengthValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important, bool strict)
    390 {
    391     const UChar* characters = string.characters();
    392     unsigned length = string.length();
    393     if (!characters || !length)
    394         return false;
    395     bool acceptsNegativeNumbers;
    396     if (!isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
    397         return false;
    398 
    399     CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
    400     if (length > 2 && characters[length - 2] == 'p' && characters[length - 1] == 'x') {
    401         length -= 2;
    402         unit = CSSPrimitiveValue::CSS_PX;
    403     } else if (length > 1 && characters[length - 1] == '%') {
    404         length -= 1;
    405         unit = CSSPrimitiveValue::CSS_PERCENTAGE;
    406     }
    407 
    408     // We rely on charactersToDouble for validation as well. The function
    409     // will set "ok" to "false" if the entire passed-in character range does
    410     // not represent a double.
    411     bool ok;
    412     double number = charactersToDouble(characters, length, &ok);
    413     if (!ok)
    414         return false;
    415     if (unit == CSSPrimitiveValue::CSS_NUMBER) {
    416         if (number && strict)
    417             return false;
    418         unit = CSSPrimitiveValue::CSS_PX;
    419     }
    420     if (number < 0 && !acceptsNegativeNumbers)
    421         return false;
    422 
    423     CSSStyleSheet* stylesheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
    424     if (!stylesheet || !stylesheet->document())
    425         return false;
    426     CSSProperty property(propertyId, stylesheet->document()->cssPrimitiveValueCache()->createValue(number, unit), important);
    427     declaration->addParsedProperty(property);
    428     return true;
    429 }
    430 
    431 bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important, bool strict)
    432 {
    433     if (parseSimpleLengthValue(declaration, propertyId, string, important, strict))
    434         return true;
    435     if (parseColorValue(declaration, propertyId, string, important, strict))
    436         return true;
    437     CSSParser parser(strict);
    438     return parser.parseValue(declaration, propertyId, string, important);
    439 }
    440 
    441 bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important)
    442 {
    443 #ifdef ANDROID_INSTRUMENT
    444     android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
    445 #endif
    446     ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
    447     setStyleSheet(static_cast<CSSStyleSheet*>(declaration->stylesheet()));
    448 
    449     setupParser("@-webkit-value{", string, "} ");
    450 
    451     m_id = propertyId;
    452     m_important = important;
    453 
    454     cssyyparse(this);
    455 
    456     m_rule = 0;
    457 
    458     bool ok = false;
    459     if (m_hasFontFaceOnlyValues)
    460         deleteFontFaceOnlyValues();
    461     if (m_numParsedProperties) {
    462         ok = true;
    463         declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
    464         clearProperties();
    465     }
    466 
    467 #ifdef ANDROID_INSTRUMENT
    468     android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
    469 #endif
    470     return ok;
    471 }
    472 
    473 // color will only be changed when string contains a valid css color, making it
    474 // possible to set up a default color.
    475 bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
    476 {
    477     // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
    478     if (parseColor(string, color, strict))
    479         return true;
    480 
    481     CSSParser parser(true);
    482     RefPtr<CSSMutableStyleDeclaration> dummyStyleDeclaration = CSSMutableStyleDeclaration::create();
    483 
    484     // Now try to create a color from rgba() syntax.
    485     if (!parser.parseColor(dummyStyleDeclaration.get(), string))
    486         return false;
    487 
    488     CSSValue* value = parser.m_parsedProperties[0]->value();
    489     if (value->cssValueType() != CSSValue::CSS_PRIMITIVE_VALUE)
    490         return false;
    491 
    492     CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
    493     if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_RGBCOLOR)
    494         return false;
    495 
    496     color = primitiveValue->getRGBA32Value();
    497     return true;
    498 }
    499 
    500 bool CSSParser::parseColor(CSSMutableStyleDeclaration* declaration, const String& string)
    501 {
    502 #ifdef ANDROID_INSTRUMENT
    503     android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
    504 #endif
    505     ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
    506     setStyleSheet(static_cast<CSSStyleSheet*>(declaration->stylesheet()));
    507 
    508     setupParser("@-webkit-decls{color:", string, "} ");
    509     cssyyparse(this);
    510     m_rule = 0;
    511 
    512 #ifdef ANDROID_INSTRUMENT
    513     android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
    514 #endif
    515     return (m_numParsedProperties && m_parsedProperties[0]->m_id == CSSPropertyColor);
    516 }
    517 
    518 bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document)
    519 {
    520     if (!document || !document->page())
    521         return false;
    522 
    523     CSSParserString cssColor;
    524     cssColor.characters = const_cast<UChar*>(string.characters());
    525     cssColor.length = string.length();
    526     int id = cssValueKeywordID(cssColor);
    527     if (id <= 0)
    528         return false;
    529 
    530     color = document->page()->theme()->systemColor(id).rgb();
    531     return true;
    532 }
    533 
    534 void CSSParser::parseSelector(const String& string, Document* doc, CSSSelectorList& selectorList)
    535 {
    536 #ifdef ANDROID_INSTRUMENT
    537     android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
    538 #endif
    539     RefPtr<CSSStyleSheet> dummyStyleSheet = CSSStyleSheet::create(doc);
    540 
    541     setStyleSheet(dummyStyleSheet.get());
    542     m_selectorListForParseSelector = &selectorList;
    543 
    544     setupParser("@-webkit-selector{", string, "}");
    545 
    546     cssyyparse(this);
    547 
    548     m_selectorListForParseSelector = 0;
    549 
    550     // The style sheet will be deleted right away, so it won't outlive the document.
    551     ASSERT(dummyStyleSheet->hasOneRef());
    552 
    553 #ifdef ANDROID_INSTRUMENT
    554     android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
    555 #endif
    556 }
    557 
    558 bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration* declaration, const String& string, RefPtr<CSSStyleSourceData>* styleSourceData)
    559 {
    560 #ifdef ANDROID_INSTRUMENT
    561     android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
    562 #endif
    563 
    564     // Length of the "@-webkit-decls{" prefix.
    565     static const unsigned prefixLength = 15;
    566 
    567     ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
    568     setStyleSheet(static_cast<CSSStyleSheet*>(declaration->stylesheet()));
    569     if (styleSourceData) {
    570         m_currentRuleData = CSSRuleSourceData::create();
    571         m_currentRuleData->styleSourceData = CSSStyleSourceData::create();
    572         m_inStyleRuleOrDeclaration = true;
    573     }
    574 
    575     setupParser("@-webkit-decls{", string, "} ");
    576     cssyyparse(this);
    577     m_rule = 0;
    578 
    579     bool ok = false;
    580     if (m_hasFontFaceOnlyValues)
    581         deleteFontFaceOnlyValues();
    582     if (m_numParsedProperties) {
    583         ok = true;
    584         declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
    585         clearProperties();
    586     }
    587 
    588     if (m_currentRuleData) {
    589         m_currentRuleData->styleSourceData->styleBodyRange.start = 0;
    590         m_currentRuleData->styleSourceData->styleBodyRange.end = string.length();
    591         for (Vector<CSSPropertySourceData>::iterator it = m_currentRuleData->styleSourceData->propertyData.begin(), endIt = m_currentRuleData->styleSourceData->propertyData.end(); it != endIt; ++it) {
    592             (*it).range.start -= prefixLength;
    593             (*it).range.end -= prefixLength;
    594         }
    595     }
    596 
    597     if (styleSourceData) {
    598         *styleSourceData = m_currentRuleData->styleSourceData.release();
    599         m_currentRuleData = 0;
    600         m_inStyleRuleOrDeclaration = false;
    601     }
    602 #ifdef ANDROID_INSTRUMENT
    603     android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
    604 #endif
    605     return ok;
    606 }
    607 
    608 bool CSSParser::parseMediaQuery(MediaList* queries, const String& string)
    609 {
    610     if (string.isEmpty())
    611         return true;
    612 
    613 #ifdef ANDROID_INSTRUMENT
    614     android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
    615 #endif
    616     ASSERT(!m_mediaQuery);
    617 
    618     // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
    619     // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
    620     setupParser("@-webkit-mediaquery ", string, "} ");
    621     cssyyparse(this);
    622 
    623     bool ok = false;
    624     if (m_mediaQuery) {
    625         ok = true;
    626         queries->appendMediaQuery(m_mediaQuery.release());
    627     }
    628 
    629 #ifdef ANDROID_INSTRUMENT
    630     android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
    631 #endif
    632     return ok;
    633 }
    634 
    635 
    636 void CSSParser::addProperty(int propId, PassRefPtr<CSSValue> value, bool important)
    637 {
    638     OwnPtr<CSSProperty> prop(new CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand));
    639     if (m_numParsedProperties >= m_maxParsedProperties) {
    640         m_maxParsedProperties += 32;
    641         if (m_maxParsedProperties > UINT_MAX / sizeof(CSSProperty*))
    642             return;
    643         m_parsedProperties = static_cast<CSSProperty**>(fastRealloc(m_parsedProperties,
    644             m_maxParsedProperties * sizeof(CSSProperty*)));
    645     }
    646     m_parsedProperties[m_numParsedProperties++] = prop.leakPtr();
    647 }
    648 
    649 void CSSParser::rollbackLastProperties(int num)
    650 {
    651     ASSERT(num >= 0);
    652     ASSERT(m_numParsedProperties >= static_cast<unsigned>(num));
    653 
    654     for (int i = 0; i < num; ++i)
    655         delete m_parsedProperties[--m_numParsedProperties];
    656 }
    657 
    658 void CSSParser::clearProperties()
    659 {
    660     for (unsigned i = 0; i < m_numParsedProperties; i++)
    661         delete m_parsedProperties[i];
    662     m_numParsedProperties = 0;
    663     m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
    664     m_hasFontFaceOnlyValues = false;
    665 }
    666 
    667 void CSSParser::setStyleSheet(CSSStyleSheet* styleSheet)
    668 {
    669     m_styleSheet = styleSheet;
    670     m_primitiveValueCache = document() ? document()->cssPrimitiveValueCache() : CSSPrimitiveValueCache::create();
    671 }
    672 
    673 Document* CSSParser::document() const
    674 {
    675     StyleBase* root = m_styleSheet;
    676     while (root && root->parent())
    677         root = root->parent();
    678     if (!root)
    679         return 0;
    680     if (!root->isCSSStyleSheet())
    681         return 0;
    682     return static_cast<CSSStyleSheet*>(root)->document();
    683 }
    684 
    685 bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, bool strict)
    686 {
    687     bool b = false;
    688     switch (value->unit) {
    689     case CSSPrimitiveValue::CSS_NUMBER:
    690         b = (unitflags & FNumber);
    691         if (!b && ((unitflags & (FLength | FAngle | FTime)) && (value->fValue == 0 || !strict))) {
    692             value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
    693                           ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
    694             b = true;
    695         }
    696         if (!b && (unitflags & FInteger) && value->isInt)
    697             b = true;
    698         break;
    699     case CSSPrimitiveValue::CSS_PERCENTAGE:
    700         b = (unitflags & FPercent);
    701         break;
    702     case CSSParserValue::Q_EMS:
    703     case CSSPrimitiveValue::CSS_EMS:
    704     case CSSPrimitiveValue::CSS_REMS:
    705     case CSSPrimitiveValue::CSS_EXS:
    706     case CSSPrimitiveValue::CSS_PX:
    707     case CSSPrimitiveValue::CSS_CM:
    708     case CSSPrimitiveValue::CSS_MM:
    709     case CSSPrimitiveValue::CSS_IN:
    710     case CSSPrimitiveValue::CSS_PT:
    711     case CSSPrimitiveValue::CSS_PC:
    712         b = (unitflags & FLength);
    713         break;
    714     case CSSPrimitiveValue::CSS_MS:
    715     case CSSPrimitiveValue::CSS_S:
    716         b = (unitflags & FTime);
    717         break;
    718     case CSSPrimitiveValue::CSS_DEG:
    719     case CSSPrimitiveValue::CSS_RAD:
    720     case CSSPrimitiveValue::CSS_GRAD:
    721     case CSSPrimitiveValue::CSS_TURN:
    722         b = (unitflags & FAngle);
    723         break;
    724     case CSSPrimitiveValue::CSS_HZ:
    725     case CSSPrimitiveValue::CSS_KHZ:
    726     case CSSPrimitiveValue::CSS_DIMENSION:
    727     default:
    728         break;
    729     }
    730     if (b && unitflags & FNonNeg && value->fValue < 0)
    731         b = false;
    732     return b;
    733 }
    734 
    735 static int unitFromString(CSSParserValue* value)
    736 {
    737     if (value->unit != CSSPrimitiveValue::CSS_IDENT || value->id)
    738         return 0;
    739 
    740     if (equal(value->string, "em"))
    741         return CSSPrimitiveValue::CSS_EMS;
    742     if (equal(value->string, "rem"))
    743         return CSSPrimitiveValue::CSS_REMS;
    744     if (equal(value->string, "ex"))
    745         return CSSPrimitiveValue::CSS_EXS;
    746     if (equal(value->string, "px"))
    747         return CSSPrimitiveValue::CSS_PX;
    748     if (equal(value->string, "cm"))
    749         return CSSPrimitiveValue::CSS_CM;
    750     if (equal(value->string, "mm"))
    751         return CSSPrimitiveValue::CSS_MM;
    752     if (equal(value->string, "in"))
    753         return CSSPrimitiveValue::CSS_IN;
    754     if (equal(value->string, "pt"))
    755         return CSSPrimitiveValue::CSS_PT;
    756     if (equal(value->string, "pc"))
    757         return CSSPrimitiveValue::CSS_PC;
    758     if (equal(value->string, "deg"))
    759         return CSSPrimitiveValue::CSS_DEG;
    760     if (equal(value->string, "rad"))
    761         return CSSPrimitiveValue::CSS_RAD;
    762     if (equal(value->string, "grad"))
    763         return CSSPrimitiveValue::CSS_GRAD;
    764     if (equal(value->string, "turn"))
    765         return CSSPrimitiveValue::CSS_TURN;
    766     if (equal(value->string, "ms"))
    767         return CSSPrimitiveValue::CSS_MS;
    768     if (equal(value->string, "s"))
    769         return CSSPrimitiveValue::CSS_S;
    770     if (equal(value->string, "Hz"))
    771         return CSSPrimitiveValue::CSS_HZ;
    772     if (equal(value->string, "kHz"))
    773         return CSSPrimitiveValue::CSS_KHZ;
    774 
    775     return 0;
    776 }
    777 
    778 void CSSParser::checkForOrphanedUnits()
    779 {
    780     if (m_strict || inShorthand())
    781         return;
    782 
    783     // The purpose of this code is to implement the WinIE quirk that allows unit types to be separated from their numeric values
    784     // 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.
    785     CSSParserValue* numericVal = 0;
    786     unsigned size = m_valueList->size();
    787     for (unsigned i = 0; i < size; i++) {
    788         CSSParserValue* value = m_valueList->valueAt(i);
    789 
    790         if (numericVal) {
    791             // Change the unit type of the numeric val to match.
    792             int unit = unitFromString(value);
    793             if (unit) {
    794                 numericVal->unit = unit;
    795                 numericVal = 0;
    796 
    797                 // Now delete the bogus unit value.
    798                 m_valueList->deleteValueAt(i);
    799                 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).
    800                 size--;
    801                 continue;
    802             }
    803         }
    804 
    805         numericVal = (value->unit == CSSPrimitiveValue::CSS_NUMBER) ? value : 0;
    806     }
    807 }
    808 
    809 bool CSSParser::parseValue(int propId, bool important)
    810 {
    811     if (!m_valueList)
    812         return false;
    813 
    814     CSSParserValue* value = m_valueList->current();
    815 
    816     if (!value)
    817         return false;
    818 
    819     int id = value->id;
    820 
    821     // In quirks mode, we will look for units that have been incorrectly separated from the number they belong to
    822     // by a space.  We go ahead and associate the unit with the number even though it is invalid CSS.
    823     checkForOrphanedUnits();
    824 
    825     int num = inShorthand() ? 1 : m_valueList->size();
    826 
    827     if (id == CSSValueInherit) {
    828         if (num != 1)
    829             return false;
    830         addProperty(propId, CSSInheritedValue::create(), important);
    831         return true;
    832     }
    833     else if (id == CSSValueInitial) {
    834         if (num != 1)
    835             return false;
    836         addProperty(propId, CSSInitialValue::createExplicit(), important);
    837         return true;
    838     }
    839 
    840     bool validPrimitive = false;
    841     RefPtr<CSSValue> parsedValue;
    842 
    843     switch (static_cast<CSSPropertyID>(propId)) {
    844         /* The comment to the left defines all valid value of this properties as defined
    845          * in CSS 2, Appendix F. Property index
    846          */
    847 
    848         /* All the CSS properties are not supported by the renderer at the moment.
    849          * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
    850          * (see parseAuralValues). As we don't support them at all this seems reasonable.
    851          */
    852 
    853     case CSSPropertySize:                 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
    854         return parseSize(propId, important);
    855 
    856     case CSSPropertyQuotes:               // [<string> <string>]+ | none | inherit
    857         if (id)
    858             validPrimitive = true;
    859         else
    860             return parseQuotes(propId, important);
    861         break;
    862     case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | inherit
    863         if (id == CSSValueNormal
    864             || id == CSSValueEmbed
    865             || id == CSSValueBidiOverride
    866             || id == CSSValueWebkitIsolate)
    867             validPrimitive = true;
    868         break;
    869 
    870     case CSSPropertyPosition:             // static | relative | absolute | fixed | inherit
    871         if (id == CSSValueStatic ||
    872              id == CSSValueRelative ||
    873              id == CSSValueAbsolute ||
    874              id == CSSValueFixed)
    875             validPrimitive = true;
    876         break;
    877 
    878     case CSSPropertyPageBreakAfter:     // auto | always | avoid | left | right | inherit
    879     case CSSPropertyPageBreakBefore:
    880     case CSSPropertyWebkitColumnBreakAfter:
    881     case CSSPropertyWebkitColumnBreakBefore:
    882         if (id == CSSValueAuto ||
    883              id == CSSValueAlways ||
    884              id == CSSValueAvoid ||
    885              id == CSSValueLeft ||
    886              id == CSSValueRight)
    887             validPrimitive = true;
    888         break;
    889 
    890     case CSSPropertyPageBreakInside:    // avoid | auto | inherit
    891     case CSSPropertyWebkitColumnBreakInside:
    892         if (id == CSSValueAuto || id == CSSValueAvoid)
    893             validPrimitive = true;
    894         break;
    895 
    896     case CSSPropertyEmptyCells:          // show | hide | inherit
    897         if (id == CSSValueShow ||
    898              id == CSSValueHide)
    899             validPrimitive = true;
    900         break;
    901 
    902     case CSSPropertyContent:              // [ <string> | <uri> | <counter> | attr(X) | open-quote |
    903         // close-quote | no-open-quote | no-close-quote ]+ | inherit
    904         return parseContent(propId, important);
    905 
    906     case CSSPropertyWhiteSpace:          // normal | pre | nowrap | inherit
    907         if (id == CSSValueNormal ||
    908             id == CSSValuePre ||
    909             id == CSSValuePreWrap ||
    910             id == CSSValuePreLine ||
    911             id == CSSValueNowrap)
    912             validPrimitive = true;
    913         break;
    914 
    915     case CSSPropertyClip:                 // <shape> | auto | inherit
    916         if (id == CSSValueAuto)
    917             validPrimitive = true;
    918         else if (value->unit == CSSParserValue::Function)
    919             return parseShape(propId, important);
    920         break;
    921 
    922     /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
    923      * correctly and allows optimization in WebCore::applyRule(..)
    924      */
    925     case CSSPropertyCaptionSide:         // top | bottom | left | right | inherit
    926         if (id == CSSValueLeft || id == CSSValueRight ||
    927             id == CSSValueTop || id == CSSValueBottom)
    928             validPrimitive = true;
    929         break;
    930 
    931     case CSSPropertyBorderCollapse:      // collapse | separate | inherit
    932         if (id == CSSValueCollapse || id == CSSValueSeparate)
    933             validPrimitive = true;
    934         break;
    935 
    936     case CSSPropertyVisibility:           // visible | hidden | collapse | inherit
    937         if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueCollapse)
    938             validPrimitive = true;
    939         break;
    940 
    941     case CSSPropertyOverflow: {
    942         ShorthandScope scope(this, propId);
    943         if (num != 1 || !parseValue(CSSPropertyOverflowX, important))
    944             return false;
    945         CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value();
    946         addProperty(CSSPropertyOverflowY, value, important);
    947         return true;
    948     }
    949     case CSSPropertyOverflowX:
    950     case CSSPropertyOverflowY:           // visible | hidden | scroll | auto | marquee | overlay | inherit
    951         if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueScroll || id == CSSValueAuto ||
    952             id == CSSValueOverlay || id == CSSValueWebkitMarquee)
    953             validPrimitive = true;
    954         break;
    955 
    956     case CSSPropertyListStylePosition:  // inside | outside | inherit
    957         if (id == CSSValueInside || id == CSSValueOutside)
    958             validPrimitive = true;
    959         break;
    960 
    961     case CSSPropertyListStyleType:
    962         // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
    963         // for the list of supported list-style-types.
    964         if ((id >= CSSValueDisc && id <= CSSValueKatakanaIroha) || id == CSSValueNone)
    965             validPrimitive = true;
    966         break;
    967 
    968     case CSSPropertyDisplay:
    969         // inline | block | list-item | run-in | inline-block | table |
    970         // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
    971         // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit
    972 #if ENABLE(WCSS)
    973         if ((id >= CSSValueInline && id <= CSSValueWapMarquee) || id == CSSValueNone)
    974 #else
    975         if ((id >= CSSValueInline && id <= CSSValueWebkitInlineBox) || id == CSSValueNone)
    976 #endif
    977             validPrimitive = true;
    978         break;
    979 
    980     case CSSPropertyDirection:            // ltr | rtl | inherit
    981         if (id == CSSValueLtr || id == CSSValueRtl)
    982             validPrimitive = true;
    983         break;
    984 
    985     case CSSPropertyTextTransform:       // capitalize | uppercase | lowercase | none | inherit
    986         if ((id >= CSSValueCapitalize && id <= CSSValueLowercase) || id == CSSValueNone)
    987             validPrimitive = true;
    988         break;
    989 
    990     case CSSPropertyFloat:                // left | right | none | inherit + center for buggy CSS
    991         if (id == CSSValueLeft || id == CSSValueRight ||
    992              id == CSSValueNone || id == CSSValueCenter)
    993             validPrimitive = true;
    994         break;
    995 
    996     case CSSPropertyClear:                // none | left | right | both | inherit
    997         if (id == CSSValueNone || id == CSSValueLeft ||
    998              id == CSSValueRight|| id == CSSValueBoth)
    999             validPrimitive = true;
   1000         break;
   1001 
   1002     case CSSPropertyTextAlign:
   1003         // left | right | center | justify | webkit_left | webkit_right | webkit_center | webkit_match_parent |
   1004         // start | end | <string> | inherit
   1005         if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
   1006              || value->unit == CSSPrimitiveValue::CSS_STRING)
   1007             validPrimitive = true;
   1008         break;
   1009 
   1010     case CSSPropertyOutlineStyle:        // (<border-style> except hidden) | auto | inherit
   1011         if (id == CSSValueAuto || id == CSSValueNone || (id >= CSSValueInset && id <= CSSValueDouble))
   1012             validPrimitive = true;
   1013         break;
   1014 
   1015     case CSSPropertyBorderTopStyle:     //// <border-style> | inherit
   1016     case CSSPropertyBorderRightStyle:   //   Defined as:    none | hidden | dotted | dashed |
   1017     case CSSPropertyBorderBottomStyle:  //   solid | double | groove | ridge | inset | outset
   1018     case CSSPropertyBorderLeftStyle:
   1019     case CSSPropertyWebkitBorderStartStyle:
   1020     case CSSPropertyWebkitBorderEndStyle:
   1021     case CSSPropertyWebkitBorderBeforeStyle:
   1022     case CSSPropertyWebkitBorderAfterStyle:
   1023     case CSSPropertyWebkitColumnRuleStyle:
   1024         if (id >= CSSValueNone && id <= CSSValueDouble)
   1025             validPrimitive = true;
   1026         break;
   1027 
   1028     case CSSPropertyFontWeight:  // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
   1029         return parseFontWeight(important);
   1030 
   1031     case CSSPropertyBorderSpacing: {
   1032         const int properties[2] = { CSSPropertyWebkitBorderHorizontalSpacing,
   1033                                     CSSPropertyWebkitBorderVerticalSpacing };
   1034         if (num == 1) {
   1035             ShorthandScope scope(this, CSSPropertyBorderSpacing);
   1036             if (!parseValue(properties[0], important))
   1037                 return false;
   1038             CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value();
   1039             addProperty(properties[1], value, important);
   1040             return true;
   1041         }
   1042         else if (num == 2) {
   1043             ShorthandScope scope(this, CSSPropertyBorderSpacing);
   1044             if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
   1045                 return false;
   1046             return true;
   1047         }
   1048         return false;
   1049     }
   1050     case CSSPropertyWebkitBorderHorizontalSpacing:
   1051     case CSSPropertyWebkitBorderVerticalSpacing:
   1052         validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
   1053         break;
   1054     case CSSPropertyOutlineColor:        // <color> | invert | inherit
   1055         // Outline color has "invert" as additional keyword.
   1056         // Also, we want to allow the special focus color even in strict parsing mode.
   1057         if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
   1058             validPrimitive = true;
   1059             break;
   1060         }
   1061         /* nobreak */
   1062     case CSSPropertyBackgroundColor: // <color> | inherit
   1063     case CSSPropertyBorderTopColor: // <color> | inherit
   1064     case CSSPropertyBorderRightColor:
   1065     case CSSPropertyBorderBottomColor:
   1066     case CSSPropertyBorderLeftColor:
   1067     case CSSPropertyWebkitBorderStartColor:
   1068     case CSSPropertyWebkitBorderEndColor:
   1069     case CSSPropertyWebkitBorderBeforeColor:
   1070     case CSSPropertyWebkitBorderAfterColor:
   1071     case CSSPropertyColor: // <color> | inherit
   1072     case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors
   1073     case CSSPropertyTextUnderlineColor:
   1074     case CSSPropertyTextOverlineColor:
   1075     case CSSPropertyWebkitColumnRuleColor:
   1076     case CSSPropertyWebkitTextEmphasisColor:
   1077     case CSSPropertyWebkitTextFillColor:
   1078     case CSSPropertyWebkitTextStrokeColor:
   1079         if (id == CSSValueWebkitText)
   1080             validPrimitive = true; // Always allow this, even when strict parsing is on,
   1081                                     // since we use this in our UA sheets.
   1082         else if (id == CSSValueCurrentcolor)
   1083             validPrimitive = true;
   1084         else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu ||
   1085              (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && !m_strict)) {
   1086             validPrimitive = true;
   1087         } else {
   1088             parsedValue = parseColor();
   1089             if (parsedValue)
   1090                 m_valueList->next();
   1091         }
   1092         break;
   1093 
   1094     case CSSPropertyCursor: {
   1095         // [<uri>,]*  [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
   1096         // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
   1097         // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
   1098         // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
   1099         // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
   1100         RefPtr<CSSValueList> list;
   1101         while (value && value->unit == CSSPrimitiveValue::CSS_URI) {
   1102             if (!list)
   1103                 list = CSSValueList::createCommaSeparated();
   1104             String uri = value->string;
   1105             Vector<int> coords;
   1106             value = m_valueList->next();
   1107             while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
   1108                 coords.append(int(value->fValue));
   1109                 value = m_valueList->next();
   1110             }
   1111             IntPoint hotSpot(-1, -1);
   1112             int nrcoords = coords.size();
   1113             if (nrcoords > 0 && nrcoords != 2)
   1114                 return false;
   1115             if (nrcoords == 2)
   1116                 hotSpot = IntPoint(coords[0], coords[1]);
   1117 
   1118             if (!uri.isNull() && m_styleSheet) {
   1119                 // FIXME: The completeURL call should be done when using the CSSCursorImageValue,
   1120                 // not when creating it.
   1121                 list->append(CSSCursorImageValue::create(m_styleSheet->completeURL(uri), hotSpot));
   1122             }
   1123 
   1124             if ((m_strict && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ',')))
   1125                 return false;
   1126             value = m_valueList->next(); // comma
   1127         }
   1128         if (list) {
   1129             if (!value) { // no value after url list (MSIE 5 compatibility)
   1130                 if (list->length() != 1)
   1131                     return false;
   1132             } else if (!m_strict && value->id == CSSValueHand) // MSIE 5 compatibility :/
   1133                 list->append(primitiveValueCache()->createIdentifierValue(CSSValuePointer));
   1134             else if (value && ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone))
   1135                 list->append(primitiveValueCache()->createIdentifierValue(value->id));
   1136             m_valueList->next();
   1137             parsedValue = list.release();
   1138             break;
   1139         }
   1140         id = value->id;
   1141         if (!m_strict && value->id == CSSValueHand) { // MSIE 5 compatibility :/
   1142             id = CSSValuePointer;
   1143             validPrimitive = true;
   1144         } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
   1145             validPrimitive = true;
   1146         break;
   1147     }
   1148 
   1149     case CSSPropertyBackgroundAttachment:
   1150     case CSSPropertyBackgroundClip:
   1151     case CSSPropertyWebkitBackgroundClip:
   1152     case CSSPropertyWebkitBackgroundComposite:
   1153     case CSSPropertyBackgroundImage:
   1154     case CSSPropertyBackgroundOrigin:
   1155     case CSSPropertyWebkitBackgroundOrigin:
   1156     case CSSPropertyBackgroundPosition:
   1157     case CSSPropertyBackgroundPositionX:
   1158     case CSSPropertyBackgroundPositionY:
   1159     case CSSPropertyBackgroundSize:
   1160     case CSSPropertyWebkitBackgroundSize:
   1161     case CSSPropertyBackgroundRepeat:
   1162     case CSSPropertyBackgroundRepeatX:
   1163     case CSSPropertyBackgroundRepeatY:
   1164     case CSSPropertyWebkitMaskAttachment:
   1165     case CSSPropertyWebkitMaskClip:
   1166     case CSSPropertyWebkitMaskComposite:
   1167     case CSSPropertyWebkitMaskImage:
   1168     case CSSPropertyWebkitMaskOrigin:
   1169     case CSSPropertyWebkitMaskPosition:
   1170     case CSSPropertyWebkitMaskPositionX:
   1171     case CSSPropertyWebkitMaskPositionY:
   1172     case CSSPropertyWebkitMaskSize:
   1173     case CSSPropertyWebkitMaskRepeat:
   1174     case CSSPropertyWebkitMaskRepeatX:
   1175     case CSSPropertyWebkitMaskRepeatY: {
   1176         RefPtr<CSSValue> val1;
   1177         RefPtr<CSSValue> val2;
   1178         int propId1, propId2;
   1179         bool result = false;
   1180         if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
   1181             OwnPtr<ShorthandScope> shorthandScope;
   1182             if (propId == CSSPropertyBackgroundPosition ||
   1183                 propId == CSSPropertyBackgroundRepeat ||
   1184                 propId == CSSPropertyWebkitMaskPosition ||
   1185                 propId == CSSPropertyWebkitMaskRepeat) {
   1186                 shorthandScope.set(new ShorthandScope(this, propId));
   1187             }
   1188             addProperty(propId1, val1.release(), important);
   1189             if (val2)
   1190                 addProperty(propId2, val2.release(), important);
   1191             result = true;
   1192         }
   1193         m_implicitShorthand = false;
   1194         return result;
   1195     }
   1196     case CSSPropertyListStyleImage:     // <uri> | none | inherit
   1197         if (id == CSSValueNone) {
   1198             parsedValue = CSSImageValue::create();
   1199             m_valueList->next();
   1200         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
   1201             if (m_styleSheet) {
   1202                 // FIXME: The completeURL call should be done when using the CSSImageValue,
   1203                 // not when creating it.
   1204                 parsedValue = CSSImageValue::create(m_styleSheet->completeURL(value->string));
   1205                 m_valueList->next();
   1206             }
   1207         } else if (isGeneratedImageValue(value)) {
   1208             if (parseGeneratedImage(parsedValue))
   1209                 m_valueList->next();
   1210             else
   1211                 return false;
   1212         }
   1213         break;
   1214 
   1215     case CSSPropertyWebkitTextStrokeWidth:
   1216     case CSSPropertyOutlineWidth:        // <border-width> | inherit
   1217     case CSSPropertyBorderTopWidth:     //// <border-width> | inherit
   1218     case CSSPropertyBorderRightWidth:   //   Which is defined as
   1219     case CSSPropertyBorderBottomWidth:  //   thin | medium | thick | <length>
   1220     case CSSPropertyBorderLeftWidth:
   1221     case CSSPropertyWebkitBorderStartWidth:
   1222     case CSSPropertyWebkitBorderEndWidth:
   1223     case CSSPropertyWebkitBorderBeforeWidth:
   1224     case CSSPropertyWebkitBorderAfterWidth:
   1225     case CSSPropertyWebkitColumnRuleWidth:
   1226         if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
   1227             validPrimitive = true;
   1228         else
   1229             validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
   1230         break;
   1231 
   1232     case CSSPropertyLetterSpacing:       // normal | <length> | inherit
   1233     case CSSPropertyWordSpacing:         // normal | <length> | inherit
   1234         if (id == CSSValueNormal)
   1235             validPrimitive = true;
   1236         else
   1237             validPrimitive = validUnit(value, FLength, m_strict);
   1238         break;
   1239 
   1240     case CSSPropertyWordBreak:          // normal | break-all | break-word (this is a custom extension)
   1241         if (id == CSSValueNormal || id == CSSValueBreakAll || id == CSSValueBreakWord)
   1242             validPrimitive = true;
   1243         break;
   1244 
   1245     case CSSPropertyWordWrap:           // normal | break-word
   1246         if (id == CSSValueNormal || id == CSSValueBreakWord)
   1247             validPrimitive = true;
   1248         break;
   1249     case CSSPropertySpeak:           // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit
   1250         if (id == CSSValueNone || id == CSSValueNormal || id == CSSValueSpellOut || id == CSSValueDigits
   1251             || id == CSSValueLiteralPunctuation || id == CSSValueNoPunctuation)
   1252             validPrimitive = true;
   1253         break;
   1254 
   1255     case CSSPropertyTextIndent:          // <length> | <percentage> | inherit
   1256         validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
   1257         break;
   1258 
   1259     case CSSPropertyPaddingTop:          //// <padding-width> | inherit
   1260     case CSSPropertyPaddingRight:        //   Which is defined as
   1261     case CSSPropertyPaddingBottom:       //   <length> | <percentage>
   1262     case CSSPropertyPaddingLeft:         ////
   1263     case CSSPropertyWebkitPaddingStart:
   1264     case CSSPropertyWebkitPaddingEnd:
   1265     case CSSPropertyWebkitPaddingBefore:
   1266     case CSSPropertyWebkitPaddingAfter:
   1267         validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
   1268         break;
   1269 
   1270     case CSSPropertyMaxHeight:           // <length> | <percentage> | none | inherit
   1271     case CSSPropertyMaxWidth:            // <length> | <percentage> | none | inherit
   1272     case CSSPropertyWebkitMaxLogicalWidth:
   1273     case CSSPropertyWebkitMaxLogicalHeight:
   1274         if (id == CSSValueNone || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) {
   1275             validPrimitive = true;
   1276             break;
   1277         }
   1278         /* nobreak */
   1279     case CSSPropertyMinHeight:           // <length> | <percentage> | inherit
   1280     case CSSPropertyMinWidth:            // <length> | <percentage> | inherit
   1281     case CSSPropertyWebkitMinLogicalWidth:
   1282     case CSSPropertyWebkitMinLogicalHeight:
   1283         if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
   1284             validPrimitive = true;
   1285         else
   1286             validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
   1287         break;
   1288 
   1289     case CSSPropertyFontSize:
   1290         // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
   1291         if (id >= CSSValueXxSmall && id <= CSSValueLarger)
   1292             validPrimitive = true;
   1293         else
   1294             validPrimitive = (validUnit(value, FLength | FPercent | FNonNeg, m_strict));
   1295         break;
   1296 
   1297     case CSSPropertyFontStyle:           // normal | italic | oblique | inherit
   1298         return parseFontStyle(important);
   1299 
   1300     case CSSPropertyFontVariant:         // normal | small-caps | inherit
   1301         return parseFontVariant(important);
   1302 
   1303     case CSSPropertyVerticalAlign:
   1304         // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
   1305         // <percentage> | <length> | inherit
   1306 
   1307         if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
   1308             validPrimitive = true;
   1309         else
   1310             validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
   1311         break;
   1312 
   1313     case CSSPropertyHeight:               // <length> | <percentage> | auto | inherit
   1314     case CSSPropertyWidth:                // <length> | <percentage> | auto | inherit
   1315     case CSSPropertyWebkitLogicalWidth:
   1316     case CSSPropertyWebkitLogicalHeight:
   1317         if (id == CSSValueAuto || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
   1318             validPrimitive = true;
   1319         else
   1320             // ### handle multilength case where we allow relative units
   1321             validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
   1322         break;
   1323 
   1324     case CSSPropertyBottom:               // <length> | <percentage> | auto | inherit
   1325     case CSSPropertyLeft:                 // <length> | <percentage> | auto | inherit
   1326     case CSSPropertyRight:                // <length> | <percentage> | auto | inherit
   1327     case CSSPropertyTop:                  // <length> | <percentage> | auto | inherit
   1328     case CSSPropertyMarginTop:           //// <margin-width> | inherit
   1329     case CSSPropertyMarginRight:         //   Which is defined as
   1330     case CSSPropertyMarginBottom:        //   <length> | <percentage> | auto | inherit
   1331     case CSSPropertyMarginLeft:          ////
   1332     case CSSPropertyWebkitMarginStart:
   1333     case CSSPropertyWebkitMarginEnd:
   1334     case CSSPropertyWebkitMarginBefore:
   1335     case CSSPropertyWebkitMarginAfter:
   1336         if (id == CSSValueAuto)
   1337             validPrimitive = true;
   1338         else
   1339             validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
   1340         break;
   1341 
   1342     case CSSPropertyZIndex:              // auto | <integer> | inherit
   1343         if (id == CSSValueAuto) {
   1344             validPrimitive = true;
   1345             break;
   1346         }
   1347         /* nobreak */
   1348     case CSSPropertyOrphans:              // <integer> | inherit
   1349     case CSSPropertyWidows:               // <integer> | inherit
   1350         // ### not supported later on
   1351         validPrimitive = (!id && validUnit(value, FInteger, false));
   1352         break;
   1353 
   1354     case CSSPropertyLineHeight:          // normal | <number> | <length> | <percentage> | inherit
   1355         if (id == CSSValueNormal)
   1356             validPrimitive = true;
   1357         else
   1358             validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict));
   1359         break;
   1360     case CSSPropertyCounterIncrement:    // [ <identifier> <integer>? ]+ | none | inherit
   1361         if (id != CSSValueNone)
   1362             return parseCounter(propId, 1, important);
   1363         validPrimitive = true;
   1364         break;
   1365      case CSSPropertyCounterReset:        // [ <identifier> <integer>? ]+ | none | inherit
   1366         if (id != CSSValueNone)
   1367             return parseCounter(propId, 0, important);
   1368         validPrimitive = true;
   1369         break;
   1370     case CSSPropertyFontFamily:
   1371         // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
   1372     {
   1373         parsedValue = parseFontFamily();
   1374         break;
   1375     }
   1376 
   1377     case CSSPropertyTextDecoration:
   1378     case CSSPropertyWebkitTextDecorationsInEffect:
   1379         // none | [ underline || overline || line-through || blink ] | inherit
   1380         if (id == CSSValueNone) {
   1381             validPrimitive = true;
   1382         } else {
   1383             RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   1384             bool isValid = true;
   1385             while (isValid && value) {
   1386                 switch (value->id) {
   1387                 case CSSValueBlink:
   1388                     break;
   1389                 case CSSValueUnderline:
   1390                 case CSSValueOverline:
   1391                 case CSSValueLineThrough:
   1392                     list->append(primitiveValueCache()->createIdentifierValue(value->id));
   1393                     break;
   1394                 default:
   1395                     isValid = false;
   1396                 }
   1397                 value = m_valueList->next();
   1398             }
   1399             if (list->length() && isValid) {
   1400                 parsedValue = list.release();
   1401                 m_valueList->next();
   1402             }
   1403         }
   1404         break;
   1405 
   1406     case CSSPropertyZoom:          // normal | reset | document | <number> | <percentage> | inherit
   1407         if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
   1408             validPrimitive = true;
   1409         else
   1410             validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, true));
   1411         break;
   1412 
   1413     case CSSPropertyTableLayout:         // auto | fixed | inherit
   1414         if (id == CSSValueAuto || id == CSSValueFixed)
   1415             validPrimitive = true;
   1416         break;
   1417 
   1418     case CSSPropertySrc:  // Only used within @font-face, so cannot use inherit | initial or be !important.  This is a list of urls or local references.
   1419         return parseFontFaceSrc();
   1420 
   1421     case CSSPropertyUnicodeRange:
   1422         return parseFontFaceUnicodeRange();
   1423 
   1424     /* CSS3 properties */
   1425     case CSSPropertyWebkitAppearance:
   1426         if ((id >= CSSValueCheckbox && id <= CSSValueTextarea) || id == CSSValueNone)
   1427             validPrimitive = true;
   1428         break;
   1429 
   1430     case CSSPropertyWebkitBorderImage:
   1431     case CSSPropertyWebkitMaskBoxImage:
   1432         if (id == CSSValueNone)
   1433             validPrimitive = true;
   1434         else {
   1435             RefPtr<CSSValue> result;
   1436             if (parseBorderImage(propId, important, result)) {
   1437                 addProperty(propId, result, important);
   1438                 return true;
   1439             }
   1440         }
   1441         break;
   1442     case CSSPropertyBorderTopRightRadius:
   1443     case CSSPropertyBorderTopLeftRadius:
   1444     case CSSPropertyBorderBottomLeftRadius:
   1445     case CSSPropertyBorderBottomRightRadius: {
   1446         if (num != 1 && num != 2)
   1447             return false;
   1448         validPrimitive = validUnit(value, FLength | FPercent, m_strict);
   1449         if (!validPrimitive)
   1450             return false;
   1451         RefPtr<CSSPrimitiveValue> parsedValue1 = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
   1452         RefPtr<CSSPrimitiveValue> parsedValue2;
   1453         if (num == 2) {
   1454             value = m_valueList->next();
   1455             validPrimitive = validUnit(value, FLength | FPercent, m_strict);
   1456             if (!validPrimitive)
   1457                 return false;
   1458             parsedValue2 = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
   1459         } else
   1460             parsedValue2 = parsedValue1;
   1461 
   1462         RefPtr<Pair> pair = Pair::create(parsedValue1.release(), parsedValue2.release());
   1463         RefPtr<CSSPrimitiveValue> val = primitiveValueCache()->createValue(pair.release());
   1464         addProperty(propId, val.release(), important);
   1465         return true;
   1466     }
   1467     case CSSPropertyBorderRadius:
   1468     case CSSPropertyWebkitBorderRadius:
   1469         return parseBorderRadius(propId, important);
   1470     case CSSPropertyOutlineOffset:
   1471         validPrimitive = validUnit(value, FLength | FPercent, m_strict);
   1472         break;
   1473     case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
   1474     case CSSPropertyBoxShadow:
   1475     case CSSPropertyWebkitBoxShadow:
   1476         if (id == CSSValueNone)
   1477             validPrimitive = true;
   1478         else
   1479             return parseShadow(propId, important);
   1480         break;
   1481     case CSSPropertyWebkitBoxReflect:
   1482         if (id == CSSValueNone)
   1483             validPrimitive = true;
   1484         else
   1485             return parseReflect(propId, important);
   1486         break;
   1487     case CSSPropertyOpacity:
   1488         validPrimitive = validUnit(value, FNumber, m_strict);
   1489         break;
   1490     case CSSPropertyWebkitBoxAlign:
   1491         if (id == CSSValueStretch || id == CSSValueStart || id == CSSValueEnd ||
   1492             id == CSSValueCenter || id == CSSValueBaseline)
   1493             validPrimitive = true;
   1494         break;
   1495     case CSSPropertyWebkitBoxDirection:
   1496         if (id == CSSValueNormal || id == CSSValueReverse)
   1497             validPrimitive = true;
   1498         break;
   1499     case CSSPropertyWebkitBoxLines:
   1500         if (id == CSSValueSingle || id == CSSValueMultiple)
   1501             validPrimitive = true;
   1502         break;
   1503     case CSSPropertyWebkitBoxOrient:
   1504         if (id == CSSValueHorizontal || id == CSSValueVertical ||
   1505             id == CSSValueInlineAxis || id == CSSValueBlockAxis)
   1506             validPrimitive = true;
   1507         break;
   1508     case CSSPropertyWebkitBoxPack:
   1509         if (id == CSSValueStart || id == CSSValueEnd ||
   1510             id == CSSValueCenter || id == CSSValueJustify)
   1511             validPrimitive = true;
   1512         break;
   1513     case CSSPropertyWebkitBoxFlex:
   1514         validPrimitive = validUnit(value, FNumber, m_strict);
   1515         break;
   1516     case CSSPropertyWebkitBoxFlexGroup:
   1517     case CSSPropertyWebkitBoxOrdinalGroup:
   1518         validPrimitive = validUnit(value, FInteger | FNonNeg, true);
   1519         break;
   1520     case CSSPropertyBoxSizing:
   1521         validPrimitive = id == CSSValueBorderBox || id == CSSValueContentBox;
   1522         break;
   1523     case CSSPropertyWebkitColorCorrection:
   1524         validPrimitive = id == CSSValueSrgb || id == CSSValueDefault;
   1525         break;
   1526     case CSSPropertyWebkitMarquee: {
   1527         const int properties[5] = { CSSPropertyWebkitMarqueeDirection, CSSPropertyWebkitMarqueeIncrement,
   1528                                     CSSPropertyWebkitMarqueeRepetition,
   1529                                     CSSPropertyWebkitMarqueeStyle, CSSPropertyWebkitMarqueeSpeed };
   1530         return parseShorthand(propId, properties, 5, important);
   1531     }
   1532     case CSSPropertyWebkitMarqueeDirection:
   1533         if (id == CSSValueForwards || id == CSSValueBackwards || id == CSSValueAhead ||
   1534             id == CSSValueReverse || id == CSSValueLeft || id == CSSValueRight || id == CSSValueDown ||
   1535             id == CSSValueUp || id == CSSValueAuto)
   1536             validPrimitive = true;
   1537         break;
   1538     case CSSPropertyWebkitMarqueeIncrement:
   1539         if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
   1540             validPrimitive = true;
   1541         else
   1542             validPrimitive = validUnit(value, FLength | FPercent, m_strict);
   1543         break;
   1544     case CSSPropertyWebkitMarqueeStyle:
   1545         if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate)
   1546             validPrimitive = true;
   1547         break;
   1548     case CSSPropertyWebkitMarqueeRepetition:
   1549         if (id == CSSValueInfinite)
   1550             validPrimitive = true;
   1551         else
   1552             validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict);
   1553         break;
   1554     case CSSPropertyWebkitMarqueeSpeed:
   1555         if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
   1556             validPrimitive = true;
   1557         else
   1558             validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict);
   1559         break;
   1560 #if ENABLE(WCSS)
   1561     case CSSPropertyWapMarqueeDir:
   1562         if (id == CSSValueLtr || id == CSSValueRtl)
   1563             validPrimitive = true;
   1564         break;
   1565     case CSSPropertyWapMarqueeStyle:
   1566         if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate)
   1567             validPrimitive = true;
   1568         break;
   1569     case CSSPropertyWapMarqueeLoop:
   1570         if (id == CSSValueInfinite)
   1571             validPrimitive = true;
   1572         else
   1573             validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict);
   1574         break;
   1575     case CSSPropertyWapMarqueeSpeed:
   1576         if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
   1577             validPrimitive = true;
   1578         else
   1579             validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict);
   1580         break;
   1581 #endif
   1582     case CSSPropertyWebkitUserDrag: // auto | none | element
   1583         if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueElement)
   1584             validPrimitive = true;
   1585         break;
   1586     case CSSPropertyWebkitUserModify: // read-only | read-write
   1587         if (id == CSSValueReadOnly || id == CSSValueReadWrite || id == CSSValueReadWritePlaintextOnly)
   1588             validPrimitive = true;
   1589         break;
   1590     case CSSPropertyWebkitUserSelect: // auto | none | text
   1591         if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueText)
   1592             validPrimitive = true;
   1593         break;
   1594     case CSSPropertyTextOverflow: // clip | ellipsis
   1595         if (id == CSSValueClip || id == CSSValueEllipsis)
   1596             validPrimitive = true;
   1597         break;
   1598     case CSSPropertyWebkitTransform:
   1599         if (id == CSSValueNone)
   1600             validPrimitive = true;
   1601         else {
   1602             PassRefPtr<CSSValue> val = parseTransform();
   1603             if (val) {
   1604                 addProperty(propId, val, important);
   1605                 return true;
   1606             }
   1607             return false;
   1608         }
   1609         break;
   1610     case CSSPropertyWebkitTransformOrigin:
   1611     case CSSPropertyWebkitTransformOriginX:
   1612     case CSSPropertyWebkitTransformOriginY:
   1613     case CSSPropertyWebkitTransformOriginZ: {
   1614         RefPtr<CSSValue> val1;
   1615         RefPtr<CSSValue> val2;
   1616         RefPtr<CSSValue> val3;
   1617         int propId1, propId2, propId3;
   1618         if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
   1619             addProperty(propId1, val1.release(), important);
   1620             if (val2)
   1621                 addProperty(propId2, val2.release(), important);
   1622             if (val3)
   1623                 addProperty(propId3, val3.release(), important);
   1624             return true;
   1625         }
   1626         return false;
   1627     }
   1628     case CSSPropertyWebkitTransformStyle:
   1629         if (value->id == CSSValueFlat || value->id == CSSValuePreserve3d)
   1630             validPrimitive = true;
   1631         break;
   1632     case CSSPropertyWebkitBackfaceVisibility:
   1633         if (value->id == CSSValueVisible || value->id == CSSValueHidden)
   1634             validPrimitive = true;
   1635         break;
   1636     case CSSPropertyWebkitPerspective:
   1637         if (id == CSSValueNone)
   1638             validPrimitive = true;
   1639         else {
   1640             // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
   1641             if (validUnit(value, FNumber | FLength | FNonNeg, m_strict)) {
   1642                 RefPtr<CSSValue> val = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
   1643                 if (val) {
   1644                     addProperty(propId, val.release(), important);
   1645                     return true;
   1646                 }
   1647                 return false;
   1648             }
   1649         }
   1650         break;
   1651     case CSSPropertyWebkitPerspectiveOrigin:
   1652     case CSSPropertyWebkitPerspectiveOriginX:
   1653     case CSSPropertyWebkitPerspectiveOriginY: {
   1654         RefPtr<CSSValue> val1;
   1655         RefPtr<CSSValue> val2;
   1656         int propId1, propId2;
   1657         if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
   1658             addProperty(propId1, val1.release(), important);
   1659             if (val2)
   1660                 addProperty(propId2, val2.release(), important);
   1661             return true;
   1662         }
   1663         return false;
   1664     }
   1665     case CSSPropertyWebkitAnimationDelay:
   1666     case CSSPropertyWebkitAnimationDirection:
   1667     case CSSPropertyWebkitAnimationDuration:
   1668     case CSSPropertyWebkitAnimationFillMode:
   1669     case CSSPropertyWebkitAnimationName:
   1670     case CSSPropertyWebkitAnimationPlayState:
   1671     case CSSPropertyWebkitAnimationIterationCount:
   1672     case CSSPropertyWebkitAnimationTimingFunction:
   1673     case CSSPropertyWebkitTransitionDelay:
   1674     case CSSPropertyWebkitTransitionDuration:
   1675     case CSSPropertyWebkitTransitionTimingFunction:
   1676     case CSSPropertyWebkitTransitionProperty: {
   1677         RefPtr<CSSValue> val;
   1678         if (parseAnimationProperty(propId, val)) {
   1679             addProperty(propId, val.release(), important);
   1680             return true;
   1681         }
   1682         return false;
   1683     }
   1684     case CSSPropertyWebkitMarginCollapse: {
   1685         const int properties[2] = { CSSPropertyWebkitMarginBeforeCollapse,
   1686             CSSPropertyWebkitMarginAfterCollapse };
   1687         if (num == 1) {
   1688             ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
   1689             if (!parseValue(properties[0], important))
   1690                 return false;
   1691             CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value();
   1692             addProperty(properties[1], value, important);
   1693             return true;
   1694         }
   1695         else if (num == 2) {
   1696             ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
   1697             if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
   1698                 return false;
   1699             return true;
   1700         }
   1701         return false;
   1702     }
   1703     case CSSPropertyWebkitMarginBeforeCollapse:
   1704     case CSSPropertyWebkitMarginAfterCollapse:
   1705     case CSSPropertyWebkitMarginTopCollapse:
   1706     case CSSPropertyWebkitMarginBottomCollapse:
   1707         if (id == CSSValueCollapse || id == CSSValueSeparate || id == CSSValueDiscard)
   1708             validPrimitive = true;
   1709         break;
   1710     case CSSPropertyTextLineThroughMode:
   1711     case CSSPropertyTextOverlineMode:
   1712     case CSSPropertyTextUnderlineMode:
   1713         if (id == CSSValueContinuous || id == CSSValueSkipWhiteSpace)
   1714             validPrimitive = true;
   1715         break;
   1716     case CSSPropertyTextLineThroughStyle:
   1717     case CSSPropertyTextOverlineStyle:
   1718     case CSSPropertyTextUnderlineStyle:
   1719         if (id == CSSValueNone || id == CSSValueSolid || id == CSSValueDouble ||
   1720             id == CSSValueDashed || id == CSSValueDotDash || id == CSSValueDotDotDash ||
   1721             id == CSSValueWave)
   1722             validPrimitive = true;
   1723         break;
   1724     case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
   1725         if (id == CSSValueAuto || id == CSSValueOptimizespeed || id == CSSValueOptimizelegibility
   1726             || id == CSSValueGeometricprecision)
   1727             validPrimitive = true;
   1728         break;
   1729     case CSSPropertyTextLineThroughWidth:
   1730     case CSSPropertyTextOverlineWidth:
   1731     case CSSPropertyTextUnderlineWidth:
   1732         if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
   1733             id == CSSValueMedium || id == CSSValueThick)
   1734             validPrimitive = true;
   1735         else
   1736             validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent, m_strict);
   1737         break;
   1738     case CSSPropertyResize: // none | both | horizontal | vertical | auto
   1739         if (id == CSSValueNone || id == CSSValueBoth || id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
   1740             validPrimitive = true;
   1741         break;
   1742     case CSSPropertyWebkitColumnCount:
   1743         if (id == CSSValueAuto)
   1744             validPrimitive = true;
   1745         else
   1746             validPrimitive = !id && validUnit(value, FInteger | FNonNeg, false);
   1747         break;
   1748     case CSSPropertyWebkitColumnGap:         // normal | <length>
   1749         if (id == CSSValueNormal)
   1750             validPrimitive = true;
   1751         else
   1752             validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
   1753         break;
   1754     case CSSPropertyWebkitColumnSpan:        // all | 1
   1755         if (id == CSSValueAll)
   1756             validPrimitive = true;
   1757         else
   1758             validPrimitive = validUnit(value, FNumber | FNonNeg, m_strict) && value->fValue == 1;
   1759         break;
   1760     case CSSPropertyWebkitColumnWidth:         // auto | <length>
   1761         if (id == CSSValueAuto)
   1762             validPrimitive = true;
   1763         else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property.
   1764             validPrimitive = validUnit(value, FLength, true);
   1765         break;
   1766     case CSSPropertyPointerEvents:
   1767         // none | visiblePainted | visibleFill | visibleStroke | visible |
   1768         // painted | fill | stroke | auto | all | inherit
   1769         if (id == CSSValueVisible || id == CSSValueNone || id == CSSValueAll || id == CSSValueAuto ||
   1770             (id >= CSSValueVisiblepainted && id <= CSSValueStroke))
   1771             validPrimitive = true;
   1772         break;
   1773 
   1774     // End of CSS3 properties
   1775 
   1776     // Apple specific properties.  These will never be standardized and are purely to
   1777     // support custom WebKit-based Apple applications.
   1778     case CSSPropertyWebkitLineClamp:
   1779         // When specifying number of lines, don't allow 0 as a valid value
   1780         // When specifying either type of unit, require non-negative integers
   1781         validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, false));
   1782         break;
   1783     case CSSPropertyWebkitTextSizeAdjust:
   1784         if (id == CSSValueAuto || id == CSSValueNone)
   1785             validPrimitive = true;
   1786         break;
   1787     case CSSPropertyWebkitRtlOrdering:
   1788         if (id == CSSValueLogical || id == CSSValueVisual)
   1789             validPrimitive = true;
   1790         break;
   1791 
   1792     case CSSPropertyWebkitFontSizeDelta:           // <length>
   1793         validPrimitive = validUnit(value, FLength, m_strict);
   1794         break;
   1795 
   1796     case CSSPropertyWebkitNbspMode:     // normal | space
   1797         if (id == CSSValueNormal || id == CSSValueSpace)
   1798             validPrimitive = true;
   1799         break;
   1800 
   1801     case CSSPropertyWebkitLineBreak:   // normal | after-white-space
   1802         if (id == CSSValueNormal || id == CSSValueAfterWhiteSpace)
   1803             validPrimitive = true;
   1804         break;
   1805 
   1806     case CSSPropertyWebkitMatchNearestMailBlockquoteColor:   // normal | match
   1807         if (id == CSSValueNormal || id == CSSValueMatch)
   1808             validPrimitive = true;
   1809         break;
   1810 
   1811     case CSSPropertyWebkitHighlight:
   1812         if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
   1813             validPrimitive = true;
   1814         break;
   1815 
   1816     case CSSPropertyWebkitHyphens:
   1817         if (id == CSSValueNone || id == CSSValueManual || id == CSSValueAuto)
   1818             validPrimitive = true;
   1819         break;
   1820 
   1821     case CSSPropertyWebkitHyphenateCharacter:
   1822         if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
   1823             validPrimitive = true;
   1824         break;
   1825 
   1826     case CSSPropertyWebkitHyphenateLimitBefore:
   1827     case CSSPropertyWebkitHyphenateLimitAfter:
   1828         if (id == CSSValueAuto || validUnit(value, FInteger | FNonNeg, true))
   1829             validPrimitive = true;
   1830         break;
   1831 
   1832     case CSSPropertyWebkitLocale:
   1833         if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
   1834             validPrimitive = true;
   1835         break;
   1836 
   1837     case CSSPropertyWebkitBorderFit:
   1838         if (id == CSSValueBorder || id == CSSValueLines)
   1839             validPrimitive = true;
   1840         break;
   1841 
   1842     case CSSPropertyWebkitTextSecurity:
   1843         // disc | circle | square | none | inherit
   1844         if (id == CSSValueDisc || id == CSSValueCircle || id == CSSValueSquare|| id == CSSValueNone)
   1845             validPrimitive = true;
   1846         break;
   1847 
   1848     case CSSPropertyWebkitFontSmoothing:
   1849         if (id == CSSValueAuto || id == CSSValueNone
   1850             || id == CSSValueAntialiased || id == CSSValueSubpixelAntialiased)
   1851             validPrimitive = true;
   1852         break;
   1853 
   1854 #if ENABLE(DASHBOARD_SUPPORT)
   1855     case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region>
   1856         if (value->unit == CSSParserValue::Function || id == CSSValueNone)
   1857             return parseDashboardRegions(propId, important);
   1858         break;
   1859 #endif
   1860     // End Apple-specific properties
   1861 
   1862         /* shorthand properties */
   1863     case CSSPropertyBackground: {
   1864         // Position must come before color in this array because a plain old "0" is a legal color
   1865         // in quirks mode but it's usually the X coordinate of a position.
   1866         // FIXME: Add CSSPropertyBackgroundSize to the shorthand.
   1867         const int properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
   1868                                    CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
   1869                                    CSSPropertyBackgroundClip, CSSPropertyBackgroundColor };
   1870         return parseFillShorthand(propId, properties, 7, important);
   1871     }
   1872     case CSSPropertyWebkitMask: {
   1873         const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
   1874                                    CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition,
   1875                                    CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip };
   1876         return parseFillShorthand(propId, properties, 6, important);
   1877     }
   1878     case CSSPropertyBorder:
   1879         // [ 'border-width' || 'border-style' || <color> ] | inherit
   1880     {
   1881         const int properties[3] = { CSSPropertyBorderWidth, CSSPropertyBorderStyle,
   1882                                     CSSPropertyBorderColor };
   1883         return parseShorthand(propId, properties, 3, important);
   1884     }
   1885     case CSSPropertyBorderTop:
   1886         // [ 'border-top-width' || 'border-style' || <color> ] | inherit
   1887     {
   1888         const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle,
   1889                                     CSSPropertyBorderTopColor};
   1890         return parseShorthand(propId, properties, 3, important);
   1891     }
   1892     case CSSPropertyBorderRight:
   1893         // [ 'border-right-width' || 'border-style' || <color> ] | inherit
   1894     {
   1895         const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle,
   1896                                     CSSPropertyBorderRightColor };
   1897         return parseShorthand(propId, properties, 3, important);
   1898     }
   1899     case CSSPropertyBorderBottom:
   1900         // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
   1901     {
   1902         const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle,
   1903                                     CSSPropertyBorderBottomColor };
   1904         return parseShorthand(propId, properties, 3, important);
   1905     }
   1906     case CSSPropertyBorderLeft:
   1907         // [ 'border-left-width' || 'border-style' || <color> ] | inherit
   1908     {
   1909         const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle,
   1910                                     CSSPropertyBorderLeftColor };
   1911         return parseShorthand(propId, properties, 3, important);
   1912     }
   1913     case CSSPropertyWebkitBorderStart:
   1914     {
   1915         const int properties[3] = { CSSPropertyWebkitBorderStartWidth, CSSPropertyWebkitBorderStartStyle,
   1916             CSSPropertyWebkitBorderStartColor };
   1917         return parseShorthand(propId, properties, 3, important);
   1918     }
   1919     case CSSPropertyWebkitBorderEnd:
   1920     {
   1921         const int properties[3] = { CSSPropertyWebkitBorderEndWidth, CSSPropertyWebkitBorderEndStyle,
   1922             CSSPropertyWebkitBorderEndColor };
   1923         return parseShorthand(propId, properties, 3, important);
   1924     }
   1925     case CSSPropertyWebkitBorderBefore:
   1926     {
   1927         const int properties[3] = { CSSPropertyWebkitBorderBeforeWidth, CSSPropertyWebkitBorderBeforeStyle,
   1928             CSSPropertyWebkitBorderBeforeColor };
   1929         return parseShorthand(propId, properties, 3, important);
   1930     }
   1931     case CSSPropertyWebkitBorderAfter:
   1932     {
   1933         const int properties[3] = { CSSPropertyWebkitBorderAfterWidth, CSSPropertyWebkitBorderAfterStyle,
   1934             CSSPropertyWebkitBorderAfterColor };
   1935         return parseShorthand(propId, properties, 3, important);
   1936     }
   1937     case CSSPropertyOutline:
   1938         // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
   1939     {
   1940         const int properties[3] = { CSSPropertyOutlineWidth, CSSPropertyOutlineStyle,
   1941                                     CSSPropertyOutlineColor };
   1942         return parseShorthand(propId, properties, 3, important);
   1943     }
   1944     case CSSPropertyBorderColor:
   1945         // <color>{1,4} | inherit
   1946     {
   1947         const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor,
   1948                                     CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor };
   1949         return parse4Values(propId, properties, important);
   1950     }
   1951     case CSSPropertyBorderWidth:
   1952         // <border-width>{1,4} | inherit
   1953     {
   1954         const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth,
   1955                                     CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth };
   1956         return parse4Values(propId, properties, important);
   1957     }
   1958     case CSSPropertyBorderStyle:
   1959         // <border-style>{1,4} | inherit
   1960     {
   1961         const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle,
   1962                                     CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle };
   1963         return parse4Values(propId, properties, important);
   1964     }
   1965     case CSSPropertyMargin:
   1966         // <margin-width>{1,4} | inherit
   1967     {
   1968         const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight,
   1969                                     CSSPropertyMarginBottom, CSSPropertyMarginLeft };
   1970         return parse4Values(propId, properties, important);
   1971     }
   1972     case CSSPropertyPadding:
   1973         // <padding-width>{1,4} | inherit
   1974     {
   1975         const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight,
   1976                                     CSSPropertyPaddingBottom, CSSPropertyPaddingLeft };
   1977         return parse4Values(propId, properties, important);
   1978     }
   1979     case CSSPropertyFont:
   1980         // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
   1981         // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
   1982         if (id >= CSSValueCaption && id <= CSSValueStatusBar)
   1983             validPrimitive = true;
   1984         else
   1985             return parseFont(important);
   1986         break;
   1987     case CSSPropertyListStyle:
   1988     {
   1989         const int properties[3] = { CSSPropertyListStyleType, CSSPropertyListStylePosition,
   1990                                     CSSPropertyListStyleImage };
   1991         return parseShorthand(propId, properties, 3, important);
   1992     }
   1993     case CSSPropertyWebkitColumns: {
   1994         const int properties[2] = { CSSPropertyWebkitColumnWidth, CSSPropertyWebkitColumnCount };
   1995         return parseShorthand(propId, properties, 2, important);
   1996     }
   1997     case CSSPropertyWebkitColumnRule: {
   1998         const int properties[3] = { CSSPropertyWebkitColumnRuleWidth, CSSPropertyWebkitColumnRuleStyle,
   1999                                     CSSPropertyWebkitColumnRuleColor };
   2000         return parseShorthand(propId, properties, 3, important);
   2001     }
   2002     case CSSPropertyWebkitTextStroke: {
   2003         const int properties[2] = { CSSPropertyWebkitTextStrokeWidth, CSSPropertyWebkitTextStrokeColor };
   2004         return parseShorthand(propId, properties, 2, important);
   2005     }
   2006     case CSSPropertyWebkitAnimation:
   2007         return parseAnimationShorthand(important);
   2008     case CSSPropertyWebkitTransition:
   2009         return parseTransitionShorthand(important);
   2010     case CSSPropertyInvalid:
   2011         return false;
   2012     case CSSPropertyPage:
   2013         return parsePage(propId, important);
   2014     case CSSPropertyFontStretch:
   2015     case CSSPropertyTextLineThrough:
   2016     case CSSPropertyTextOverline:
   2017     case CSSPropertyTextUnderline:
   2018         return false;
   2019 
   2020 #if ENABLE(WCSS)
   2021     case CSSPropertyWapInputFormat:
   2022         validPrimitive = true;
   2023         break;
   2024     case CSSPropertyWapInputRequired:
   2025         parsedValue = parseWCSSInputProperty();
   2026         break;
   2027 #endif
   2028 
   2029     // CSS Text Layout Module Level 3: Vertical writing support
   2030     case CSSPropertyWebkitWritingMode:
   2031         if (id >= CSSValueHorizontalTb && id <= CSSValueHorizontalBt)
   2032             validPrimitive = true;
   2033         break;
   2034 
   2035     case CSSPropertyWebkitTextCombine:
   2036         if (id == CSSValueNone || id == CSSValueHorizontal)
   2037             validPrimitive = true;
   2038         break;
   2039 
   2040     case CSSPropertyWebkitTextEmphasis: {
   2041         const int properties[] = { CSSPropertyWebkitTextEmphasisStyle, CSSPropertyWebkitTextEmphasisColor };
   2042         return parseShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
   2043     }
   2044 
   2045     case CSSPropertyWebkitTextEmphasisPosition:
   2046         if (id == CSSValueOver || id == CSSValueUnder)
   2047             validPrimitive = true;
   2048         break;
   2049 
   2050     case CSSPropertyWebkitTextEmphasisStyle:
   2051         return parseTextEmphasisStyle(important);
   2052 
   2053     case CSSPropertyWebkitTextOrientation:
   2054         // FIXME: For now just support upright and vertical-right.
   2055         if (id == CSSValueVerticalRight || id == CSSValueUpright)
   2056             validPrimitive = true;
   2057         break;
   2058 
   2059     case CSSPropertyWebkitLineBoxContain:
   2060         if (id == CSSValueNone)
   2061             validPrimitive = true;
   2062         else
   2063             return parseLineBoxContain(important);
   2064         break;
   2065 
   2066 #ifdef ANDROID_CSS_RING
   2067     case CSSPropertyWebkitRing:
   2068     {
   2069         const int properties[9] = { CSSPropertyWebkitRingFillColor,
   2070                                     CSSPropertyWebkitRingInnerWidth,
   2071                                     CSSPropertyWebkitRingOuterWidth,
   2072                                     CSSPropertyWebkitRingOutset,
   2073                                     CSSPropertyWebkitRingPressedInnerColor,
   2074                                     CSSPropertyWebkitRingPressedOuterColor,
   2075                                     CSSPropertyWebkitRingRadius,
   2076                                     CSSPropertyWebkitRingSelectedInnerColor,
   2077                                     CSSPropertyWebkitRingSelectedOuterColor };
   2078         return parseShorthand(propId, properties, 9, important);
   2079     }
   2080     case CSSPropertyWebkitRingFillColor:
   2081     case CSSPropertyWebkitRingPressedInnerColor:
   2082     case CSSPropertyWebkitRingPressedOuterColor:
   2083     case CSSPropertyWebkitRingSelectedInnerColor:
   2084     case CSSPropertyWebkitRingSelectedOuterColor:
   2085         parsedValue = parseColor();
   2086         if (parsedValue)
   2087             m_valueList->next();
   2088         break;
   2089     case CSSPropertyWebkitRingInnerWidth:
   2090     case CSSPropertyWebkitRingOuterWidth:
   2091     case CSSPropertyWebkitRingOutset:
   2092     case CSSPropertyWebkitRingRadius:
   2093         validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
   2094         break;
   2095 #endif
   2096 #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
   2097     case CSSPropertyWebkitTapHighlightColor:
   2098         parsedValue = parseColor();
   2099         if (parsedValue)
   2100             m_valueList->next();
   2101         break;
   2102 #endif
   2103 
   2104 #if ENABLE(SVG)
   2105     default:
   2106         return parseSVGValue(propId, important);
   2107 #endif
   2108     }
   2109 
   2110     if (validPrimitive) {
   2111         if (id != 0)
   2112             parsedValue = primitiveValueCache()->createIdentifierValue(id);
   2113         else if (value->unit == CSSPrimitiveValue::CSS_STRING)
   2114             parsedValue = primitiveValueCache()->createValue(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
   2115         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
   2116             parsedValue = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
   2117         else if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS)
   2118             parsedValue = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
   2119         else if (value->unit >= CSSParserValue::Q_EMS)
   2120             parsedValue = CSSQuirkPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_EMS);
   2121         m_valueList->next();
   2122     }
   2123     if (parsedValue) {
   2124         if (!m_valueList->current() || inShorthand()) {
   2125             addProperty(propId, parsedValue.release(), important);
   2126             return true;
   2127         }
   2128     }
   2129     return false;
   2130 }
   2131 
   2132 #if ENABLE(WCSS)
   2133 PassRefPtr<CSSValue> CSSParser::parseWCSSInputProperty()
   2134 {
   2135     RefPtr<CSSValue> parsedValue = 0;
   2136     CSSParserValue* value = m_valueList->current();
   2137     String inputProperty;
   2138     if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT)
   2139         inputProperty = String(value->string);
   2140 
   2141     if (!inputProperty.isEmpty())
   2142        parsedValue = primitiveValueCache()->createValue(inputProperty, CSSPrimitiveValue::CSS_STRING);
   2143 
   2144     while (m_valueList->next()) {
   2145     // pass all other values, if any. If we don't do this,
   2146     // the parser will think that it's not done and won't process this property
   2147     }
   2148 
   2149     return parsedValue;
   2150 }
   2151 #endif
   2152 
   2153 void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
   2154 {
   2155     if (lval) {
   2156         if (lval->isValueList())
   2157             static_cast<CSSValueList*>(lval.get())->append(rval);
   2158         else {
   2159             PassRefPtr<CSSValue> oldlVal(lval.release());
   2160             PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
   2161             list->append(oldlVal);
   2162             list->append(rval);
   2163             lval = list;
   2164         }
   2165     }
   2166     else
   2167         lval = rval;
   2168 }
   2169 
   2170 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue, CSSPrimitiveValueCache* primitiveValueCache)
   2171 {
   2172     if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
   2173         || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
   2174         cssValue = primitiveValueCache->createIdentifierValue(parserValue->id);
   2175         return true;
   2176     }
   2177     return false;
   2178 }
   2179 
   2180 const int cMaxFillProperties = 9;
   2181 
   2182 bool CSSParser::parseFillShorthand(int propId, const int* properties, int numProperties, bool important)
   2183 {
   2184     ASSERT(numProperties <= cMaxFillProperties);
   2185     if (numProperties > cMaxFillProperties)
   2186         return false;
   2187 
   2188     ShorthandScope scope(this, propId);
   2189 
   2190     bool parsedProperty[cMaxFillProperties] = { false };
   2191     RefPtr<CSSValue> values[cMaxFillProperties];
   2192     RefPtr<CSSValue> clipValue;
   2193     RefPtr<CSSValue> positionYValue;
   2194     RefPtr<CSSValue> repeatYValue;
   2195     bool foundClip = false;
   2196     int i;
   2197 
   2198     while (m_valueList->current()) {
   2199         CSSParserValue* val = m_valueList->current();
   2200         if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   2201             // We hit the end.  Fill in all remaining values with the initial value.
   2202             m_valueList->next();
   2203             for (i = 0; i < numProperties; ++i) {
   2204                 if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
   2205                     // Color is not allowed except as the last item in a list for backgrounds.
   2206                     // Reject the entire property.
   2207                     return false;
   2208 
   2209                 if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
   2210                     addFillValue(values[i], CSSInitialValue::createImplicit());
   2211                     if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
   2212                         addFillValue(positionYValue, CSSInitialValue::createImplicit());
   2213                     if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
   2214                         addFillValue(repeatYValue, CSSInitialValue::createImplicit());
   2215                     if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
   2216                         // If background-origin wasn't present, then reset background-clip also.
   2217                         addFillValue(clipValue, CSSInitialValue::createImplicit());
   2218                     }
   2219                 }
   2220                 parsedProperty[i] = false;
   2221             }
   2222             if (!m_valueList->current())
   2223                 break;
   2224         }
   2225 
   2226         bool found = false;
   2227         for (i = 0; !found && i < numProperties; ++i) {
   2228             if (!parsedProperty[i]) {
   2229                 RefPtr<CSSValue> val1;
   2230                 RefPtr<CSSValue> val2;
   2231                 int propId1, propId2;
   2232                 CSSParserValue* parserValue = m_valueList->current();
   2233                 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
   2234                     parsedProperty[i] = found = true;
   2235                     addFillValue(values[i], val1.release());
   2236                     if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
   2237                         addFillValue(positionYValue, val2.release());
   2238                     if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
   2239                         addFillValue(repeatYValue, val2.release());
   2240                     if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
   2241                         // Reparse the value as a clip, and see if we succeed.
   2242                         if (parseBackgroundClip(parserValue, val1, primitiveValueCache()))
   2243                             addFillValue(clipValue, val1.release()); // The property parsed successfully.
   2244                         else
   2245                             addFillValue(clipValue, CSSInitialValue::createImplicit()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
   2246                     }
   2247                     if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
   2248                         // Update clipValue
   2249                         addFillValue(clipValue, val1.release());
   2250                         foundClip = true;
   2251                     }
   2252                 }
   2253             }
   2254         }
   2255 
   2256         // if we didn't find at least one match, this is an
   2257         // invalid shorthand and we have to ignore it
   2258         if (!found)
   2259             return false;
   2260     }
   2261 
   2262     // Fill in any remaining properties with the initial value.
   2263     for (i = 0; i < numProperties; ++i) {
   2264         if (!parsedProperty[i]) {
   2265             addFillValue(values[i], CSSInitialValue::createImplicit());
   2266             if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
   2267                 addFillValue(positionYValue, CSSInitialValue::createImplicit());
   2268             if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
   2269                 addFillValue(repeatYValue, CSSInitialValue::createImplicit());
   2270             if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
   2271                 // If background-origin wasn't present, then reset background-clip also.
   2272                 addFillValue(clipValue, CSSInitialValue::createImplicit());
   2273             }
   2274         }
   2275     }
   2276 
   2277     // Now add all of the properties we found.
   2278     for (i = 0; i < numProperties; i++) {
   2279         if (properties[i] == CSSPropertyBackgroundPosition) {
   2280             addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
   2281             // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
   2282             addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
   2283         } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
   2284             addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
   2285             // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
   2286             addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
   2287         } else if (properties[i] == CSSPropertyBackgroundRepeat) {
   2288             addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
   2289             // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
   2290             addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
   2291         } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
   2292             addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
   2293             // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
   2294             addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
   2295         } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
   2296             // Value is already set while updating origin
   2297             continue;
   2298         else
   2299             addProperty(properties[i], values[i].release(), important);
   2300 
   2301         // Add in clip values when we hit the corresponding origin property.
   2302         if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
   2303             addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
   2304         else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
   2305             addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
   2306     }
   2307 
   2308     return true;
   2309 }
   2310 
   2311 void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
   2312 {
   2313     if (lval) {
   2314         if (lval->isValueList())
   2315             static_cast<CSSValueList*>(lval.get())->append(rval);
   2316         else {
   2317             PassRefPtr<CSSValue> oldVal(lval.release());
   2318             PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
   2319             list->append(oldVal);
   2320             list->append(rval);
   2321             lval = list;
   2322         }
   2323     }
   2324     else
   2325         lval = rval;
   2326 }
   2327 
   2328 bool CSSParser::parseAnimationShorthand(bool important)
   2329 {
   2330     const int properties[] = {  CSSPropertyWebkitAnimationName,
   2331                                 CSSPropertyWebkitAnimationDuration,
   2332                                 CSSPropertyWebkitAnimationTimingFunction,
   2333                                 CSSPropertyWebkitAnimationDelay,
   2334                                 CSSPropertyWebkitAnimationIterationCount,
   2335                                 CSSPropertyWebkitAnimationDirection,
   2336                                 CSSPropertyWebkitAnimationFillMode };
   2337     const int numProperties = WTF_ARRAY_LENGTH(properties);
   2338 
   2339     ShorthandScope scope(this, CSSPropertyWebkitAnimation);
   2340 
   2341     bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
   2342     RefPtr<CSSValue> values[numProperties];
   2343 
   2344     int i;
   2345     while (m_valueList->current()) {
   2346         CSSParserValue* val = m_valueList->current();
   2347         if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   2348             // We hit the end.  Fill in all remaining values with the initial value.
   2349             m_valueList->next();
   2350             for (i = 0; i < numProperties; ++i) {
   2351                 if (!parsedProperty[i])
   2352                     addAnimationValue(values[i], CSSInitialValue::createImplicit());
   2353                 parsedProperty[i] = false;
   2354             }
   2355             if (!m_valueList->current())
   2356                 break;
   2357         }
   2358 
   2359         bool found = false;
   2360         for (i = 0; !found && i < numProperties; ++i) {
   2361             if (!parsedProperty[i]) {
   2362                 RefPtr<CSSValue> val;
   2363                 if (parseAnimationProperty(properties[i], val)) {
   2364                     parsedProperty[i] = found = true;
   2365                     addAnimationValue(values[i], val.release());
   2366                 }
   2367             }
   2368         }
   2369 
   2370         // if we didn't find at least one match, this is an
   2371         // invalid shorthand and we have to ignore it
   2372         if (!found)
   2373             return false;
   2374     }
   2375 
   2376     // Fill in any remaining properties with the initial value.
   2377     for (i = 0; i < numProperties; ++i) {
   2378         if (!parsedProperty[i])
   2379             addAnimationValue(values[i], CSSInitialValue::createImplicit());
   2380     }
   2381 
   2382     // Now add all of the properties we found.
   2383     for (i = 0; i < numProperties; i++)
   2384         addProperty(properties[i], values[i].release(), important);
   2385 
   2386     return true;
   2387 }
   2388 
   2389 bool CSSParser::parseTransitionShorthand(bool important)
   2390 {
   2391     const int properties[] = { CSSPropertyWebkitTransitionProperty,
   2392                                CSSPropertyWebkitTransitionDuration,
   2393                                CSSPropertyWebkitTransitionTimingFunction,
   2394                                CSSPropertyWebkitTransitionDelay };
   2395     const int numProperties = WTF_ARRAY_LENGTH(properties);
   2396 
   2397     ShorthandScope scope(this, CSSPropertyWebkitTransition);
   2398 
   2399     bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
   2400     RefPtr<CSSValue> values[numProperties];
   2401 
   2402     int i;
   2403     while (m_valueList->current()) {
   2404         CSSParserValue* val = m_valueList->current();
   2405         if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   2406             // We hit the end.  Fill in all remaining values with the initial value.
   2407             m_valueList->next();
   2408             for (i = 0; i < numProperties; ++i) {
   2409                 if (!parsedProperty[i])
   2410                     addAnimationValue(values[i], CSSInitialValue::createImplicit());
   2411                 parsedProperty[i] = false;
   2412             }
   2413             if (!m_valueList->current())
   2414                 break;
   2415         }
   2416 
   2417         bool found = false;
   2418         for (i = 0; !found && i < numProperties; ++i) {
   2419             if (!parsedProperty[i]) {
   2420                 RefPtr<CSSValue> val;
   2421                 if (parseAnimationProperty(properties[i], val)) {
   2422                     parsedProperty[i] = found = true;
   2423                     addAnimationValue(values[i], val.release());
   2424                 }
   2425             }
   2426         }
   2427 
   2428         // if we didn't find at least one match, this is an
   2429         // invalid shorthand and we have to ignore it
   2430         if (!found)
   2431             return false;
   2432     }
   2433 
   2434     // Fill in any remaining properties with the initial value.
   2435     for (i = 0; i < numProperties; ++i) {
   2436         if (!parsedProperty[i])
   2437             addAnimationValue(values[i], CSSInitialValue::createImplicit());
   2438     }
   2439 
   2440     // Now add all of the properties we found.
   2441     for (i = 0; i < numProperties; i++)
   2442         addProperty(properties[i], values[i].release(), important);
   2443 
   2444     return true;
   2445 }
   2446 
   2447 bool CSSParser::parseShorthand(int propId, const int *properties, int numProperties, bool important)
   2448 {
   2449     // We try to match as many properties as possible
   2450     // We set up an array of booleans to mark which property has been found,
   2451     // and we try to search for properties until it makes no longer any sense.
   2452     ShorthandScope scope(this, propId);
   2453 
   2454     bool found = false;
   2455     bool fnd[6]; // Trust me ;)
   2456     for (int i = 0; i < numProperties; i++)
   2457         fnd[i] = false;
   2458 
   2459     while (m_valueList->current()) {
   2460         found = false;
   2461         for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
   2462             if (!fnd[propIndex]) {
   2463                 if (parseValue(properties[propIndex], important))
   2464                     fnd[propIndex] = found = true;
   2465             }
   2466         }
   2467 
   2468         // if we didn't find at least one match, this is an
   2469         // invalid shorthand and we have to ignore it
   2470         if (!found)
   2471             return false;
   2472     }
   2473 
   2474     // Fill in any remaining properties with the initial value.
   2475     m_implicitShorthand = true;
   2476     for (int i = 0; i < numProperties; ++i) {
   2477         if (!fnd[i])
   2478             addProperty(properties[i], CSSInitialValue::createImplicit(), important);
   2479     }
   2480     m_implicitShorthand = false;
   2481 
   2482     return true;
   2483 }
   2484 
   2485 bool CSSParser::parse4Values(int propId, const int *properties,  bool important)
   2486 {
   2487     /* From the CSS 2 specs, 8.3
   2488      * If there is only one value, it applies to all sides. If there are two values, the top and
   2489      * bottom margins are set to the first value and the right and left margins are set to the second.
   2490      * If there are three values, the top is set to the first value, the left and right are set to the
   2491      * second, and the bottom is set to the third. If there are four values, they apply to the top,
   2492      * right, bottom, and left, respectively.
   2493      */
   2494 
   2495     int num = inShorthand() ? 1 : m_valueList->size();
   2496 
   2497     ShorthandScope scope(this, propId);
   2498 
   2499     // the order is top, right, bottom, left
   2500     switch (num) {
   2501         case 1: {
   2502             if (!parseValue(properties[0], important))
   2503                 return false;
   2504             CSSValue *value = m_parsedProperties[m_numParsedProperties-1]->value();
   2505             m_implicitShorthand = true;
   2506             addProperty(properties[1], value, important);
   2507             addProperty(properties[2], value, important);
   2508             addProperty(properties[3], value, important);
   2509             m_implicitShorthand = false;
   2510             break;
   2511         }
   2512         case 2: {
   2513             if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
   2514                 return false;
   2515             CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value();
   2516             m_implicitShorthand = true;
   2517             addProperty(properties[2], value, important);
   2518             value = m_parsedProperties[m_numParsedProperties-2]->value();
   2519             addProperty(properties[3], value, important);
   2520             m_implicitShorthand = false;
   2521             break;
   2522         }
   2523         case 3: {
   2524             if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
   2525                 return false;
   2526             CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value();
   2527             m_implicitShorthand = true;
   2528             addProperty(properties[3], value, important);
   2529             m_implicitShorthand = false;
   2530             break;
   2531         }
   2532         case 4: {
   2533             if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
   2534                 !parseValue(properties[2], important) || !parseValue(properties[3], important))
   2535                 return false;
   2536             break;
   2537         }
   2538         default: {
   2539             return false;
   2540         }
   2541     }
   2542 
   2543     return true;
   2544 }
   2545 
   2546 // auto | <identifier>
   2547 bool CSSParser::parsePage(int propId, bool important)
   2548 {
   2549     ASSERT(propId == CSSPropertyPage);
   2550 
   2551     if (m_valueList->size() != 1)
   2552         return false;
   2553 
   2554     CSSParserValue* value = m_valueList->current();
   2555     if (!value)
   2556         return false;
   2557 
   2558     if (value->id == CSSValueAuto) {
   2559         addProperty(propId, primitiveValueCache()->createIdentifierValue(value->id), important);
   2560         return true;
   2561     } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
   2562         addProperty(propId, primitiveValueCache()->createValue(value->string, CSSPrimitiveValue::CSS_STRING), important);
   2563         return true;
   2564     }
   2565     return false;
   2566 }
   2567 
   2568 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
   2569 bool CSSParser::parseSize(int propId, bool important)
   2570 {
   2571     ASSERT(propId == CSSPropertySize);
   2572 
   2573     if (m_valueList->size() > 2)
   2574         return false;
   2575 
   2576     CSSParserValue* value = m_valueList->current();
   2577     if (!value)
   2578         return false;
   2579 
   2580     RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
   2581 
   2582     // First parameter.
   2583     SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
   2584     if (paramType == None)
   2585         return false;
   2586 
   2587     // Second parameter, if any.
   2588     value = m_valueList->next();
   2589     if (value) {
   2590         paramType = parseSizeParameter(parsedValues.get(), value, paramType);
   2591         if (paramType == None)
   2592             return false;
   2593     }
   2594 
   2595     addProperty(propId, parsedValues.release(), important);
   2596     return true;
   2597 }
   2598 
   2599 CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
   2600 {
   2601     switch (value->id) {
   2602     case CSSValueAuto:
   2603         if (prevParamType == None) {
   2604             parsedValues->append(primitiveValueCache()->createIdentifierValue(value->id));
   2605             return Auto;
   2606         }
   2607         return None;
   2608     case CSSValueLandscape:
   2609     case CSSValuePortrait:
   2610         if (prevParamType == None || prevParamType == PageSize) {
   2611             parsedValues->append(primitiveValueCache()->createIdentifierValue(value->id));
   2612             return Orientation;
   2613         }
   2614         return None;
   2615     case CSSValueA3:
   2616     case CSSValueA4:
   2617     case CSSValueA5:
   2618     case CSSValueB4:
   2619     case CSSValueB5:
   2620     case CSSValueLedger:
   2621     case CSSValueLegal:
   2622     case CSSValueLetter:
   2623         if (prevParamType == None || prevParamType == Orientation) {
   2624             // Normalize to Page Size then Orientation order by prepending.
   2625             // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (CSSStyleSelector::applyPageSizeProperty).
   2626             parsedValues->prepend(primitiveValueCache()->createIdentifierValue(value->id));
   2627             return PageSize;
   2628         }
   2629         return None;
   2630     case 0:
   2631         if (validUnit(value, FLength | FNonNeg, m_strict) && (prevParamType == None || prevParamType == Length)) {
   2632             parsedValues->append(primitiveValueCache()->createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
   2633             return Length;
   2634         }
   2635         return None;
   2636     default:
   2637         return None;
   2638     }
   2639 }
   2640 
   2641 // [ <string> <string> ]+ | inherit | none
   2642 // inherit and none are handled in parseValue.
   2643 bool CSSParser::parseQuotes(int propId, bool important)
   2644 {
   2645     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
   2646     while (CSSParserValue* val = m_valueList->current()) {
   2647         RefPtr<CSSValue> parsedValue;
   2648         if (val->unit == CSSPrimitiveValue::CSS_STRING)
   2649             parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
   2650         else
   2651             break;
   2652         values->append(parsedValue.release());
   2653         m_valueList->next();
   2654     }
   2655     if (values->length()) {
   2656         addProperty(propId, values.release(), important);
   2657         m_valueList->next();
   2658         return true;
   2659     }
   2660     return false;
   2661 }
   2662 
   2663 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
   2664 // in CSS 2.1 this got somewhat reduced:
   2665 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
   2666 bool CSSParser::parseContent(int propId, bool important)
   2667 {
   2668     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
   2669 
   2670     while (CSSParserValue* val = m_valueList->current()) {
   2671         RefPtr<CSSValue> parsedValue;
   2672         if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
   2673             // url
   2674             // FIXME: The completeURL call should be done when using the CSSImageValue,
   2675             // not when creating it.
   2676             parsedValue = CSSImageValue::create(m_styleSheet->completeURL(val->string));
   2677         } else if (val->unit == CSSParserValue::Function) {
   2678             // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
   2679             CSSParserValueList* args = val->function->args.get();
   2680             if (!args)
   2681                 return false;
   2682             if (equalIgnoringCase(val->function->name, "attr(")) {
   2683                 parsedValue = parseAttr(args);
   2684                 if (!parsedValue)
   2685                     return false;
   2686             } else if (equalIgnoringCase(val->function->name, "counter(")) {
   2687                 parsedValue = parseCounterContent(args, false);
   2688                 if (!parsedValue)
   2689                     return false;
   2690             } else if (equalIgnoringCase(val->function->name, "counters(")) {
   2691                 parsedValue = parseCounterContent(args, true);
   2692                 if (!parsedValue)
   2693                     return false;
   2694             } else if (isGeneratedImageValue(val)) {
   2695                 if (!parseGeneratedImage(parsedValue))
   2696                     return false;
   2697             } else
   2698                 return false;
   2699         } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
   2700             // open-quote
   2701             // close-quote
   2702             // no-open-quote
   2703             // no-close-quote
   2704             // inherit
   2705             // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
   2706             // none
   2707             // normal
   2708             switch (val->id) {
   2709             case CSSValueOpenQuote:
   2710             case CSSValueCloseQuote:
   2711             case CSSValueNoOpenQuote:
   2712             case CSSValueNoCloseQuote:
   2713             case CSSValueNone:
   2714             case CSSValueNormal:
   2715                 parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
   2716             }
   2717         } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
   2718             parsedValue = primitiveValueCache()->createValue(val->string, CSSPrimitiveValue::CSS_STRING);
   2719         }
   2720         if (!parsedValue)
   2721             break;
   2722         values->append(parsedValue.release());
   2723         m_valueList->next();
   2724     }
   2725 
   2726     if (values->length()) {
   2727         addProperty(propId, values.release(), important);
   2728         m_valueList->next();
   2729         return true;
   2730     }
   2731 
   2732     return false;
   2733 }
   2734 
   2735 PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args)
   2736 {
   2737     if (args->size() != 1)
   2738         return 0;
   2739 
   2740     CSSParserValue* a = args->current();
   2741 
   2742     if (a->unit != CSSPrimitiveValue::CSS_IDENT)
   2743         return 0;
   2744 
   2745     String attrName = a->string;
   2746     // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
   2747     // But HTML attribute names can't have those characters, and we should not
   2748     // even parse them inside attr().
   2749     if (attrName[0] == '-')
   2750         return 0;
   2751 
   2752     if (document() && document()->isHTMLDocument())
   2753         attrName = attrName.lower();
   2754 
   2755     return primitiveValueCache()->createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
   2756 }
   2757 
   2758 PassRefPtr<CSSValue> CSSParser::parseBackgroundColor()
   2759 {
   2760     int id = m_valueList->current()->id;
   2761     if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
   2762         (id >= CSSValueGrey && id < CSSValueWebkitText && !m_strict))
   2763        return primitiveValueCache()->createIdentifierValue(id);
   2764     return parseColor();
   2765 }
   2766 
   2767 bool CSSParser::parseFillImage(RefPtr<CSSValue>& value)
   2768 {
   2769     if (m_valueList->current()->id == CSSValueNone) {
   2770         value = CSSImageValue::create();
   2771         return true;
   2772     }
   2773     if (m_valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
   2774         // FIXME: The completeURL call should be done when using the CSSImageValue,
   2775         // not when creating it.
   2776         if (m_styleSheet)
   2777             value = CSSImageValue::create(m_styleSheet->completeURL(m_valueList->current()->string));
   2778         return true;
   2779     }
   2780 
   2781     if (isGeneratedImageValue(m_valueList->current()))
   2782         return parseGeneratedImage(value);
   2783 
   2784     return false;
   2785 }
   2786 
   2787 PassRefPtr<CSSValue> CSSParser::parseFillPositionX(CSSParserValueList* valueList)
   2788 {
   2789     int id = valueList->current()->id;
   2790     if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
   2791         int percent = 0;
   2792         if (id == CSSValueRight)
   2793             percent = 100;
   2794         else if (id == CSSValueCenter)
   2795             percent = 50;
   2796         return primitiveValueCache()->createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
   2797     }
   2798     if (validUnit(valueList->current(), FPercent | FLength, m_strict))
   2799         return primitiveValueCache()->createValue(valueList->current()->fValue,
   2800                                                   (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
   2801     return 0;
   2802 }
   2803 
   2804 PassRefPtr<CSSValue> CSSParser::parseFillPositionY(CSSParserValueList* valueList)
   2805 {
   2806     int id = valueList->current()->id;
   2807     if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
   2808         int percent = 0;
   2809         if (id == CSSValueBottom)
   2810             percent = 100;
   2811         else if (id == CSSValueCenter)
   2812             percent = 50;
   2813         return primitiveValueCache()->createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
   2814     }
   2815     if (validUnit(valueList->current(), FPercent | FLength, m_strict))
   2816         return primitiveValueCache()->createValue(valueList->current()->fValue,
   2817                                                   (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
   2818     return 0;
   2819 }
   2820 
   2821 PassRefPtr<CSSValue> CSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag)
   2822 {
   2823     int id = valueList->current()->id;
   2824     if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
   2825         int percent = 0;
   2826         if (id == CSSValueLeft || id == CSSValueRight) {
   2827             if (cumulativeFlags & XFillPosition)
   2828                 return 0;
   2829             cumulativeFlags |= XFillPosition;
   2830             individualFlag = XFillPosition;
   2831             if (id == CSSValueRight)
   2832                 percent = 100;
   2833         }
   2834         else if (id == CSSValueTop || id == CSSValueBottom) {
   2835             if (cumulativeFlags & YFillPosition)
   2836                 return 0;
   2837             cumulativeFlags |= YFillPosition;
   2838             individualFlag = YFillPosition;
   2839             if (id == CSSValueBottom)
   2840                 percent = 100;
   2841         } else if (id == CSSValueCenter) {
   2842             // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
   2843             percent = 50;
   2844             cumulativeFlags |= AmbiguousFillPosition;
   2845             individualFlag = AmbiguousFillPosition;
   2846         }
   2847         return primitiveValueCache()->createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
   2848     }
   2849     if (validUnit(valueList->current(), FPercent | FLength, m_strict)) {
   2850         if (!cumulativeFlags) {
   2851             cumulativeFlags |= XFillPosition;
   2852             individualFlag = XFillPosition;
   2853         } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
   2854             cumulativeFlags |= YFillPosition;
   2855             individualFlag = YFillPosition;
   2856         } else
   2857             return 0;
   2858         return primitiveValueCache()->createValue(valueList->current()->fValue,
   2859                                                   (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
   2860     }
   2861     return 0;
   2862 }
   2863 
   2864 void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
   2865 {
   2866     CSSParserValue* value = valueList->current();
   2867 
   2868     // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
   2869     unsigned cumulativeFlags = 0;
   2870     FillPositionFlag value1Flag = InvalidFillPosition;
   2871     FillPositionFlag value2Flag = InvalidFillPosition;
   2872     value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
   2873     if (!value1)
   2874         return;
   2875 
   2876     // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
   2877     // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
   2878     // value was explicitly specified for our property.
   2879     value = valueList->next();
   2880 
   2881     // First check for the comma.  If so, we are finished parsing this value or value pair.
   2882     if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
   2883         value = 0;
   2884 
   2885     if (value) {
   2886         value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
   2887         if (value2)
   2888             valueList->next();
   2889         else {
   2890             if (!inShorthand()) {
   2891                 value1.clear();
   2892                 return;
   2893             }
   2894         }
   2895     }
   2896 
   2897     if (!value2)
   2898         // Only one value was specified.  If that value was not a keyword, then it sets the x position, and the y position
   2899         // is simply 50%.  This is our default.
   2900         // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
   2901         // For left/right/center, the default of 50% in the y is still correct.
   2902         value2 = primitiveValueCache()->createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
   2903 
   2904     if (value1Flag == YFillPosition || value2Flag == XFillPosition)
   2905         value1.swap(value2);
   2906 }
   2907 
   2908 void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
   2909 {
   2910     CSSParserValue* value = m_valueList->current();
   2911 
   2912     int id = m_valueList->current()->id;
   2913     if (id == CSSValueRepeatX) {
   2914         m_implicitShorthand = true;
   2915         value1 = primitiveValueCache()->createIdentifierValue(CSSValueRepeat);
   2916         value2 = primitiveValueCache()->createIdentifierValue(CSSValueNoRepeat);
   2917         m_valueList->next();
   2918         return;
   2919     }
   2920     if (id == CSSValueRepeatY) {
   2921         m_implicitShorthand = true;
   2922         value1 = primitiveValueCache()->createIdentifierValue(CSSValueNoRepeat);
   2923         value2 = primitiveValueCache()->createIdentifierValue(CSSValueRepeat);
   2924         m_valueList->next();
   2925         return;
   2926     }
   2927     if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
   2928         value1 = primitiveValueCache()->createIdentifierValue(id);
   2929     else {
   2930         value1 = 0;
   2931         return;
   2932     }
   2933 
   2934     value = m_valueList->next();
   2935 
   2936     // First check for the comma.  If so, we are finished parsing this value or value pair.
   2937     if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
   2938         value = 0;
   2939 
   2940     if (value)
   2941         id = m_valueList->current()->id;
   2942 
   2943     if (value && (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)) {
   2944         value2 = primitiveValueCache()->createIdentifierValue(id);
   2945         m_valueList->next();
   2946     } else {
   2947         // If only one value was specified, value2 is the same as value1.
   2948         m_implicitShorthand = true;
   2949         value2 = primitiveValueCache()->createIdentifierValue(static_cast<CSSPrimitiveValue*>(value1.get())->getIdent());
   2950     }
   2951 }
   2952 
   2953 PassRefPtr<CSSValue> CSSParser::parseFillSize(int propId, bool& allowComma)
   2954 {
   2955     allowComma = true;
   2956     CSSParserValue* value = m_valueList->current();
   2957 
   2958     if (value->id == CSSValueContain || value->id == CSSValueCover)
   2959         return primitiveValueCache()->createIdentifierValue(value->id);
   2960 
   2961     RefPtr<CSSPrimitiveValue> parsedValue1;
   2962 
   2963     if (value->id == CSSValueAuto)
   2964         parsedValue1 = primitiveValueCache()->createValue(0, CSSPrimitiveValue::CSS_UNKNOWN);
   2965     else {
   2966         if (!validUnit(value, FLength | FPercent, m_strict))
   2967             return 0;
   2968         parsedValue1 = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
   2969     }
   2970 
   2971     CSSPropertyID property = static_cast<CSSPropertyID>(propId);
   2972     RefPtr<CSSPrimitiveValue> parsedValue2;
   2973     if ((value = m_valueList->next())) {
   2974         if (value->id == CSSValueAuto)
   2975             parsedValue2 = primitiveValueCache()->createValue(0, CSSPrimitiveValue::CSS_UNKNOWN);
   2976         else if (value->unit == CSSParserValue::Operator && value->iValue == ',')
   2977             allowComma = false;
   2978         else {
   2979             if (!validUnit(value, FLength | FPercent, m_strict))
   2980                 return 0;
   2981             parsedValue2 = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
   2982         }
   2983     }
   2984     if (!parsedValue2) {
   2985         if (property == CSSPropertyWebkitBackgroundSize || property == CSSPropertyWebkitMaskSize)
   2986             parsedValue2 = parsedValue1;
   2987         else
   2988             parsedValue2 = primitiveValueCache()->createValue(0, CSSPrimitiveValue::CSS_UNKNOWN);
   2989     }
   2990 
   2991     return primitiveValueCache()->createValue(Pair::create(parsedValue1.release(), parsedValue2.release()));
   2992 }
   2993 
   2994 bool CSSParser::parseFillProperty(int propId, int& propId1, int& propId2,
   2995                                   RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
   2996 {
   2997     RefPtr<CSSValueList> values;
   2998     RefPtr<CSSValueList> values2;
   2999     CSSParserValue* val;
   3000     RefPtr<CSSValue> value;
   3001     RefPtr<CSSValue> value2;
   3002 
   3003     bool allowComma = false;
   3004 
   3005     retValue1 = retValue2 = 0;
   3006     propId1 = propId;
   3007     propId2 = propId;
   3008     if (propId == CSSPropertyBackgroundPosition) {
   3009         propId1 = CSSPropertyBackgroundPositionX;
   3010         propId2 = CSSPropertyBackgroundPositionY;
   3011     } else if (propId == CSSPropertyWebkitMaskPosition) {
   3012         propId1 = CSSPropertyWebkitMaskPositionX;
   3013         propId2 = CSSPropertyWebkitMaskPositionY;
   3014     } else if (propId == CSSPropertyBackgroundRepeat) {
   3015         propId1 = CSSPropertyBackgroundRepeatX;
   3016         propId2 = CSSPropertyBackgroundRepeatY;
   3017     } else if (propId == CSSPropertyWebkitMaskRepeat) {
   3018         propId1 = CSSPropertyWebkitMaskRepeatX;
   3019         propId2 = CSSPropertyWebkitMaskRepeatY;
   3020     }
   3021 
   3022     while ((val = m_valueList->current())) {
   3023         RefPtr<CSSValue> currValue;
   3024         RefPtr<CSSValue> currValue2;
   3025 
   3026         if (allowComma) {
   3027             if (val->unit != CSSParserValue::Operator || val->iValue != ',')
   3028                 return false;
   3029             m_valueList->next();
   3030             allowComma = false;
   3031         } else {
   3032             allowComma = true;
   3033             switch (propId) {
   3034                 case CSSPropertyBackgroundColor:
   3035                     currValue = parseBackgroundColor();
   3036                     if (currValue)
   3037                         m_valueList->next();
   3038                     break;
   3039                 case CSSPropertyBackgroundAttachment:
   3040                 case CSSPropertyWebkitMaskAttachment:
   3041                     if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
   3042                         currValue = primitiveValueCache()->createIdentifierValue(val->id);
   3043                         m_valueList->next();
   3044                     }
   3045                     break;
   3046                 case CSSPropertyBackgroundImage:
   3047                 case CSSPropertyWebkitMaskImage:
   3048                     if (parseFillImage(currValue))
   3049                         m_valueList->next();
   3050                     break;
   3051                 case CSSPropertyWebkitBackgroundClip:
   3052                 case CSSPropertyWebkitBackgroundOrigin:
   3053                 case CSSPropertyWebkitMaskClip:
   3054                 case CSSPropertyWebkitMaskOrigin:
   3055                     // The first three values here are deprecated and do not apply to the version of the property that has
   3056                     // the -webkit- prefix removed.
   3057                     if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
   3058                         val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
   3059                         ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
   3060                          (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
   3061                         currValue = primitiveValueCache()->createIdentifierValue(val->id);
   3062                         m_valueList->next();
   3063                     }
   3064                     break;
   3065                 case CSSPropertyBackgroundClip:
   3066                     if (parseBackgroundClip(val, currValue, primitiveValueCache()))
   3067                         m_valueList->next();
   3068                     break;
   3069                 case CSSPropertyBackgroundOrigin:
   3070                     if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
   3071                         currValue = primitiveValueCache()->createIdentifierValue(val->id);
   3072                         m_valueList->next();
   3073                     }
   3074                     break;
   3075                 case CSSPropertyBackgroundPosition:
   3076                 case CSSPropertyWebkitMaskPosition:
   3077                     parseFillPosition(m_valueList, currValue, currValue2);
   3078                     // parseFillPosition advances the m_valueList pointer
   3079                     break;
   3080                 case CSSPropertyBackgroundPositionX:
   3081                 case CSSPropertyWebkitMaskPositionX: {
   3082                     currValue = parseFillPositionX(m_valueList);
   3083                     if (currValue)
   3084                         m_valueList->next();
   3085                     break;
   3086                 }
   3087                 case CSSPropertyBackgroundPositionY:
   3088                 case CSSPropertyWebkitMaskPositionY: {
   3089                     currValue = parseFillPositionY(m_valueList);
   3090                     if (currValue)
   3091                         m_valueList->next();
   3092                     break;
   3093                 }
   3094                 case CSSPropertyWebkitBackgroundComposite:
   3095                 case CSSPropertyWebkitMaskComposite:
   3096                     if ((val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) || val->id == CSSValueHighlight) {
   3097                         currValue = primitiveValueCache()->createIdentifierValue(val->id);
   3098                         m_valueList->next();
   3099                     }
   3100                     break;
   3101                 case CSSPropertyBackgroundRepeat:
   3102                 case CSSPropertyWebkitMaskRepeat:
   3103                     parseFillRepeat(currValue, currValue2);
   3104                     // parseFillRepeat advances the m_valueList pointer
   3105                     break;
   3106                 case CSSPropertyBackgroundSize:
   3107                 case CSSPropertyWebkitBackgroundSize:
   3108                 case CSSPropertyWebkitMaskSize: {
   3109                     currValue = parseFillSize(propId, allowComma);
   3110                     if (currValue)
   3111                         m_valueList->next();
   3112                     break;
   3113                 }
   3114             }
   3115             if (!currValue)
   3116                 return false;
   3117 
   3118             if (value && !values) {
   3119                 values = CSSValueList::createCommaSeparated();
   3120                 values->append(value.release());
   3121             }
   3122 
   3123             if (value2 && !values2) {
   3124                 values2 = CSSValueList::createCommaSeparated();
   3125                 values2->append(value2.release());
   3126             }
   3127 
   3128             if (values)
   3129                 values->append(currValue.release());
   3130             else
   3131                 value = currValue.release();
   3132             if (currValue2) {
   3133                 if (values2)
   3134                     values2->append(currValue2.release());
   3135                 else
   3136                     value2 = currValue2.release();
   3137             }
   3138         }
   3139 
   3140         // When parsing any fill shorthand property, we let it handle building up the lists for all
   3141         // properties.
   3142         if (inShorthand())
   3143             break;
   3144     }
   3145 
   3146     if (values && values->length()) {
   3147         retValue1 = values.release();
   3148         if (values2 && values2->length())
   3149             retValue2 = values2.release();
   3150         return true;
   3151     }
   3152     if (value) {
   3153         retValue1 = value.release();
   3154         retValue2 = value2.release();
   3155         return true;
   3156     }
   3157     return false;
   3158 }
   3159 
   3160 PassRefPtr<CSSValue> CSSParser::parseAnimationDelay()
   3161 {
   3162     CSSParserValue* value = m_valueList->current();
   3163     if (validUnit(value, FTime, m_strict))
   3164         return primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
   3165     return 0;
   3166 }
   3167 
   3168 PassRefPtr<CSSValue> CSSParser::parseAnimationDirection()
   3169 {
   3170     CSSParserValue* value = m_valueList->current();
   3171     if (value->id == CSSValueNormal || value->id == CSSValueAlternate)
   3172         return primitiveValueCache()->createIdentifierValue(value->id);
   3173     return 0;
   3174 }
   3175 
   3176 PassRefPtr<CSSValue> CSSParser::parseAnimationDuration()
   3177 {
   3178     CSSParserValue* value = m_valueList->current();
   3179     if (validUnit(value, FTime | FNonNeg, m_strict))
   3180         return primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
   3181     return 0;
   3182 }
   3183 
   3184 PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode()
   3185 {
   3186     CSSParserValue* value = m_valueList->current();
   3187     if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
   3188         return primitiveValueCache()->createIdentifierValue(value->id);
   3189     return 0;
   3190 }
   3191 
   3192 PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount()
   3193 {
   3194     CSSParserValue* value = m_valueList->current();
   3195     if (value->id == CSSValueInfinite)
   3196         return primitiveValueCache()->createIdentifierValue(value->id);
   3197     if (validUnit(value, FInteger | FNonNeg, m_strict))
   3198         return primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
   3199     return 0;
   3200 }
   3201 
   3202 PassRefPtr<CSSValue> CSSParser::parseAnimationName()
   3203 {
   3204     CSSParserValue* value = m_valueList->current();
   3205     if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
   3206         if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value->string, "none"))) {
   3207             return primitiveValueCache()->createIdentifierValue(CSSValueNone);
   3208         } else {
   3209             return primitiveValueCache()->createValue(value->string, CSSPrimitiveValue::CSS_STRING);
   3210         }
   3211     }
   3212     return 0;
   3213 }
   3214 
   3215 PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState()
   3216 {
   3217     CSSParserValue* value = m_valueList->current();
   3218     if (value->id == CSSValueRunning || value->id == CSSValuePaused)
   3219         return primitiveValueCache()->createIdentifierValue(value->id);
   3220     return 0;
   3221 }
   3222 
   3223 PassRefPtr<CSSValue> CSSParser::parseAnimationProperty()
   3224 {
   3225     CSSParserValue* value = m_valueList->current();
   3226     if (value->unit != CSSPrimitiveValue::CSS_IDENT)
   3227         return 0;
   3228     int result = cssPropertyID(value->string);
   3229     if (result)
   3230         return primitiveValueCache()->createIdentifierValue(result);
   3231     if (equalIgnoringCase(value->string, "all"))
   3232         return primitiveValueCache()->createIdentifierValue(CSSValueAll);
   3233     if (equalIgnoringCase(value->string, "none"))
   3234         return primitiveValueCache()->createIdentifierValue(CSSValueNone);
   3235     return 0;
   3236 }
   3237 
   3238 bool CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
   3239 {
   3240     parseFillPosition(m_valueList, value1, value2);
   3241 
   3242     // now get z
   3243     if (m_valueList->current()) {
   3244         if (validUnit(m_valueList->current(), FLength, m_strict)) {
   3245             value3 = primitiveValueCache()->createValue(m_valueList->current()->fValue,
   3246                                              (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit);
   3247             m_valueList->next();
   3248             return true;
   3249         }
   3250         return false;
   3251     }
   3252     return true;
   3253 }
   3254 
   3255 bool CSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
   3256 {
   3257     CSSParserValue* v = args->current();
   3258     if (!validUnit(v, FNumber, m_strict))
   3259         return false;
   3260     result = v->fValue;
   3261     if (result < 0 || result > 1.0)
   3262         return false;
   3263     v = args->next();
   3264     if (!v)
   3265         // The last number in the function has no comma after it, so we're done.
   3266         return true;
   3267     if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   3268         return false;
   3269     v = args->next();
   3270     return true;
   3271 }
   3272 
   3273 PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction()
   3274 {
   3275     CSSParserValue* value = m_valueList->current();
   3276     if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
   3277         || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd)
   3278         return primitiveValueCache()->createIdentifierValue(value->id);
   3279 
   3280     // We must be a function.
   3281     if (value->unit != CSSParserValue::Function)
   3282         return 0;
   3283 
   3284     CSSParserValueList* args = value->function->args.get();
   3285 
   3286     if (equalIgnoringCase(value->function->name, "steps(")) {
   3287         // For steps, 1 or 2 params must be specified (comma-separated)
   3288         if (!args || (args->size() != 1 && args->size() != 3))
   3289             return 0;
   3290 
   3291         // There are two values.
   3292         int numSteps;
   3293         bool stepAtStart = false;
   3294 
   3295         CSSParserValue* v = args->current();
   3296         if (!validUnit(v, FInteger, m_strict))
   3297             return 0;
   3298         numSteps = (int) min(v->fValue, (double)INT_MAX);
   3299         if (numSteps < 1)
   3300             return 0;
   3301         v = args->next();
   3302 
   3303         if (v) {
   3304             // There is a comma so we need to parse the second value
   3305             if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   3306                 return 0;
   3307             v = args->next();
   3308             if (v->id != CSSValueStart && v->id != CSSValueEnd)
   3309                 return 0;
   3310             stepAtStart = v->id == CSSValueStart;
   3311         }
   3312 
   3313         return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart);
   3314     }
   3315 
   3316     if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
   3317         // For cubic bezier, 4 values must be specified.
   3318         if (!args || args->size() != 7)
   3319             return 0;
   3320 
   3321         // There are two points specified.  The values must be between 0 and 1.
   3322         double x1, y1, x2, y2;
   3323 
   3324         if (!parseCubicBezierTimingFunctionValue(args, x1))
   3325             return 0;
   3326         if (!parseCubicBezierTimingFunctionValue(args, y1))
   3327             return 0;
   3328         if (!parseCubicBezierTimingFunctionValue(args, x2))
   3329             return 0;
   3330         if (!parseCubicBezierTimingFunctionValue(args, y2))
   3331             return 0;
   3332 
   3333         return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
   3334     }
   3335 
   3336     return 0;
   3337 }
   3338 
   3339 bool CSSParser::parseAnimationProperty(int propId, RefPtr<CSSValue>& result)
   3340 {
   3341     RefPtr<CSSValueList> values;
   3342     CSSParserValue* val;
   3343     RefPtr<CSSValue> value;
   3344     bool allowComma = false;
   3345 
   3346     result = 0;
   3347 
   3348     while ((val = m_valueList->current())) {
   3349         RefPtr<CSSValue> currValue;
   3350         if (allowComma) {
   3351             if (val->unit != CSSParserValue::Operator || val->iValue != ',')
   3352                 return false;
   3353             m_valueList->next();
   3354             allowComma = false;
   3355         }
   3356         else {
   3357             switch (propId) {
   3358                 case CSSPropertyWebkitAnimationDelay:
   3359                 case CSSPropertyWebkitTransitionDelay:
   3360                     currValue = parseAnimationDelay();
   3361                     if (currValue)
   3362                         m_valueList->next();
   3363                     break;
   3364                 case CSSPropertyWebkitAnimationDirection:
   3365                     currValue = parseAnimationDirection();
   3366                     if (currValue)
   3367                         m_valueList->next();
   3368                     break;
   3369                 case CSSPropertyWebkitAnimationDuration:
   3370                 case CSSPropertyWebkitTransitionDuration:
   3371                     currValue = parseAnimationDuration();
   3372                     if (currValue)
   3373                         m_valueList->next();
   3374                     break;
   3375                 case CSSPropertyWebkitAnimationFillMode:
   3376                     currValue = parseAnimationFillMode();
   3377                     if (currValue)
   3378                         m_valueList->next();
   3379                     break;
   3380                 case CSSPropertyWebkitAnimationIterationCount:
   3381                     currValue = parseAnimationIterationCount();
   3382                     if (currValue)
   3383                         m_valueList->next();
   3384                     break;
   3385                 case CSSPropertyWebkitAnimationName:
   3386                     currValue = parseAnimationName();
   3387                     if (currValue)
   3388                         m_valueList->next();
   3389                     break;
   3390                 case CSSPropertyWebkitAnimationPlayState:
   3391                     currValue = parseAnimationPlayState();
   3392                     if (currValue)
   3393                         m_valueList->next();
   3394                     break;
   3395                 case CSSPropertyWebkitTransitionProperty:
   3396                     currValue = parseAnimationProperty();
   3397                     if (currValue)
   3398                         m_valueList->next();
   3399                     break;
   3400                 case CSSPropertyWebkitAnimationTimingFunction:
   3401                 case CSSPropertyWebkitTransitionTimingFunction:
   3402                     currValue = parseAnimationTimingFunction();
   3403                     if (currValue)
   3404                         m_valueList->next();
   3405                     break;
   3406             }
   3407 
   3408             if (!currValue)
   3409                 return false;
   3410 
   3411             if (value && !values) {
   3412                 values = CSSValueList::createCommaSeparated();
   3413                 values->append(value.release());
   3414             }
   3415 
   3416             if (values)
   3417                 values->append(currValue.release());
   3418             else
   3419                 value = currValue.release();
   3420 
   3421             allowComma = true;
   3422         }
   3423 
   3424         // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
   3425         // properties.
   3426         if (inShorthand())
   3427             break;
   3428     }
   3429 
   3430     if (values && values->length()) {
   3431         result = values.release();
   3432         return true;
   3433     }
   3434     if (value) {
   3435         result = value.release();
   3436         return true;
   3437     }
   3438     return false;
   3439 }
   3440 
   3441 
   3442 
   3443 #if ENABLE(DASHBOARD_SUPPORT)
   3444 
   3445 #define DASHBOARD_REGION_NUM_PARAMETERS  6
   3446 #define DASHBOARD_REGION_SHORT_NUM_PARAMETERS  2
   3447 
   3448 static CSSParserValue* skipCommaInDashboardRegion(CSSParserValueList *args)
   3449 {
   3450     if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) ||
   3451          args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
   3452         CSSParserValue* current = args->current();
   3453         if (current->unit == CSSParserValue::Operator && current->iValue == ',')
   3454             return args->next();
   3455     }
   3456     return args->current();
   3457 }
   3458 
   3459 bool CSSParser::parseDashboardRegions(int propId, bool important)
   3460 {
   3461     bool valid = true;
   3462 
   3463     CSSParserValue* value = m_valueList->current();
   3464 
   3465     if (value->id == CSSValueNone) {
   3466         if (m_valueList->next())
   3467             return false;
   3468         addProperty(propId, primitiveValueCache()->createIdentifierValue(value->id), important);
   3469         return valid;
   3470     }
   3471 
   3472     RefPtr<DashboardRegion> firstRegion = DashboardRegion::create();
   3473     DashboardRegion* region = 0;
   3474 
   3475     while (value) {
   3476         if (region == 0) {
   3477             region = firstRegion.get();
   3478         } else {
   3479             RefPtr<DashboardRegion> nextRegion = DashboardRegion::create();
   3480             region->m_next = nextRegion;
   3481             region = nextRegion.get();
   3482         }
   3483 
   3484         if (value->unit != CSSParserValue::Function) {
   3485             valid = false;
   3486             break;
   3487         }
   3488 
   3489         // Commas count as values, so allow:
   3490         // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
   3491         // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
   3492         // also allow
   3493         // dashboard-region(label, type) or dashboard-region(label type)
   3494         // dashboard-region(label, type) or dashboard-region(label type)
   3495         CSSParserValueList* args = value->function->args.get();
   3496         if (!equalIgnoringCase(value->function->name, "dashboard-region(") || !args) {
   3497             valid = false;
   3498             break;
   3499         }
   3500 
   3501         int numArgs = args->size();
   3502         if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) &&
   3503             (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))) {
   3504             valid = false;
   3505             break;
   3506         }
   3507 
   3508         // First arg is a label.
   3509         CSSParserValue* arg = args->current();
   3510         if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
   3511             valid = false;
   3512             break;
   3513         }
   3514 
   3515         region->m_label = arg->string;
   3516 
   3517         // Second arg is a type.
   3518         arg = args->next();
   3519         arg = skipCommaInDashboardRegion(args);
   3520         if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
   3521             valid = false;
   3522             break;
   3523         }
   3524 
   3525         if (equalIgnoringCase(arg->string, "circle"))
   3526             region->m_isCircle = true;
   3527         else if (equalIgnoringCase(arg->string, "rectangle"))
   3528             region->m_isRectangle = true;
   3529         else {
   3530             valid = false;
   3531             break;
   3532         }
   3533 
   3534         region->m_geometryType = arg->string;
   3535 
   3536         if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
   3537             // This originally used CSSValueInvalid by accident. It might be more logical to use something else.
   3538             RefPtr<CSSPrimitiveValue> amount = primitiveValueCache()->createIdentifierValue(CSSValueInvalid);
   3539 
   3540             region->setTop(amount);
   3541             region->setRight(amount);
   3542             region->setBottom(amount);
   3543             region->setLeft(amount);
   3544         } else {
   3545             // Next four arguments must be offset numbers
   3546             int i;
   3547             for (i = 0; i < 4; i++) {
   3548                 arg = args->next();
   3549                 arg = skipCommaInDashboardRegion(args);
   3550 
   3551                 valid = arg->id == CSSValueAuto || validUnit(arg, FLength, m_strict);
   3552                 if (!valid)
   3553                     break;
   3554 
   3555                 RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ?
   3556                     primitiveValueCache()->createIdentifierValue(CSSValueAuto) :
   3557                     primitiveValueCache()->createValue(arg->fValue, (CSSPrimitiveValue::UnitTypes) arg->unit);
   3558 
   3559                 if (i == 0)
   3560                     region->setTop(amount);
   3561                 else if (i == 1)
   3562                     region->setRight(amount);
   3563                 else if (i == 2)
   3564                     region->setBottom(amount);
   3565                 else
   3566                     region->setLeft(amount);
   3567             }
   3568         }
   3569 
   3570         if (args->next())
   3571             return false;
   3572 
   3573         value = m_valueList->next();
   3574     }
   3575 
   3576     if (valid)
   3577         addProperty(propId, primitiveValueCache()->createValue(firstRegion.release()), important);
   3578 
   3579     return valid;
   3580 }
   3581 
   3582 #endif /* ENABLE(DASHBOARD_SUPPORT) */
   3583 
   3584 PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
   3585 {
   3586     unsigned numArgs = args->size();
   3587     if (counters && numArgs != 3 && numArgs != 5)
   3588         return 0;
   3589     if (!counters && numArgs != 1 && numArgs != 3)
   3590         return 0;
   3591 
   3592     CSSParserValue* i = args->current();
   3593     if (i->unit != CSSPrimitiveValue::CSS_IDENT)
   3594         return 0;
   3595     RefPtr<CSSPrimitiveValue> identifier = primitiveValueCache()->createValue(i->string, CSSPrimitiveValue::CSS_STRING);
   3596 
   3597     RefPtr<CSSPrimitiveValue> separator;
   3598     if (!counters)
   3599         separator = primitiveValueCache()->createValue(String(), CSSPrimitiveValue::CSS_STRING);
   3600     else {
   3601         i = args->next();
   3602         if (i->unit != CSSParserValue::Operator || i->iValue != ',')
   3603             return 0;
   3604 
   3605         i = args->next();
   3606         if (i->unit != CSSPrimitiveValue::CSS_STRING)
   3607             return 0;
   3608 
   3609         separator = primitiveValueCache()->createValue(i->string, (CSSPrimitiveValue::UnitTypes) i->unit);
   3610     }
   3611 
   3612     RefPtr<CSSPrimitiveValue> listStyle;
   3613     i = args->next();
   3614     if (!i) // Make the list style default decimal
   3615         listStyle = primitiveValueCache()->createValue(CSSValueDecimal - CSSValueDisc, CSSPrimitiveValue::CSS_NUMBER);
   3616     else {
   3617         if (i->unit != CSSParserValue::Operator || i->iValue != ',')
   3618             return 0;
   3619 
   3620         i = args->next();
   3621         if (i->unit != CSSPrimitiveValue::CSS_IDENT)
   3622             return 0;
   3623 
   3624         short ls = 0;
   3625         if (i->id == CSSValueNone)
   3626             ls = CSSValueKatakanaIroha - CSSValueDisc + 1;
   3627         else if (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha)
   3628             ls = i->id - CSSValueDisc;
   3629         else
   3630             return 0;
   3631 
   3632         listStyle = primitiveValueCache()->createValue(ls, (CSSPrimitiveValue::UnitTypes) i->unit);
   3633     }
   3634 
   3635     return primitiveValueCache()->createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
   3636 }
   3637 
   3638 bool CSSParser::parseShape(int propId, bool important)
   3639 {
   3640     CSSParserValue* value = m_valueList->current();
   3641     CSSParserValueList* args = value->function->args.get();
   3642 
   3643     if (!equalIgnoringCase(value->function->name, "rect(") || !args)
   3644         return false;
   3645 
   3646     // rect(t, r, b, l) || rect(t r b l)
   3647     if (args->size() != 4 && args->size() != 7)
   3648         return false;
   3649     RefPtr<Rect> rect = Rect::create();
   3650     bool valid = true;
   3651     int i = 0;
   3652     CSSParserValue* a = args->current();
   3653     while (a) {
   3654         valid = a->id == CSSValueAuto || validUnit(a, FLength, m_strict);
   3655         if (!valid)
   3656             break;
   3657         RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
   3658             primitiveValueCache()->createIdentifierValue(CSSValueAuto) :
   3659             primitiveValueCache()->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
   3660         if (i == 0)
   3661             rect->setTop(length);
   3662         else if (i == 1)
   3663             rect->setRight(length);
   3664         else if (i == 2)
   3665             rect->setBottom(length);
   3666         else
   3667             rect->setLeft(length);
   3668         a = args->next();
   3669         if (a && args->size() == 7) {
   3670             if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
   3671                 a = args->next();
   3672             } else {
   3673                 valid = false;
   3674                 break;
   3675             }
   3676         }
   3677         i++;
   3678     }
   3679     if (valid) {
   3680         addProperty(propId, primitiveValueCache()->createValue(rect.release()), important);
   3681         m_valueList->next();
   3682         return true;
   3683     }
   3684     return false;
   3685 }
   3686 
   3687 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
   3688 bool CSSParser::parseFont(bool important)
   3689 {
   3690     bool valid = true;
   3691     CSSParserValue *value = m_valueList->current();
   3692     RefPtr<FontValue> font = FontValue::create();
   3693     // optional font-style, font-variant and font-weight
   3694     while (value) {
   3695         int id = value->id;
   3696         if (id) {
   3697             if (id == CSSValueNormal) {
   3698                 // do nothing, it's the inital value for all three
   3699             } else if (id == CSSValueItalic || id == CSSValueOblique) {
   3700                 if (font->style)
   3701                     return false;
   3702                 font->style = primitiveValueCache()->createIdentifierValue(id);
   3703             } else if (id == CSSValueSmallCaps) {
   3704                 if (font->variant)
   3705                     return false;
   3706                 font->variant = primitiveValueCache()->createIdentifierValue(id);
   3707             } else if (id >= CSSValueBold && id <= CSSValueLighter) {
   3708                 if (font->weight)
   3709                     return false;
   3710                 font->weight = primitiveValueCache()->createIdentifierValue(id);
   3711             } else {
   3712                 valid = false;
   3713             }
   3714         } else if (!font->weight && validUnit(value, FInteger | FNonNeg, true)) {
   3715             int weight = (int)value->fValue;
   3716             int val = 0;
   3717             if (weight == 100)
   3718                 val = CSSValue100;
   3719             else if (weight == 200)
   3720                 val = CSSValue200;
   3721             else if (weight == 300)
   3722                 val = CSSValue300;
   3723             else if (weight == 400)
   3724                 val = CSSValue400;
   3725             else if (weight == 500)
   3726                 val = CSSValue500;
   3727             else if (weight == 600)
   3728                 val = CSSValue600;
   3729             else if (weight == 700)
   3730                 val = CSSValue700;
   3731             else if (weight == 800)
   3732                 val = CSSValue800;
   3733             else if (weight == 900)
   3734                 val = CSSValue900;
   3735 
   3736             if (val)
   3737                 font->weight = primitiveValueCache()->createIdentifierValue(val);
   3738             else
   3739                 valid = false;
   3740         } else {
   3741             valid = false;
   3742         }
   3743         if (!valid)
   3744             break;
   3745         value = m_valueList->next();
   3746     }
   3747     if (!value)
   3748         return false;
   3749 
   3750     // set undefined values to default
   3751     if (!font->style)
   3752         font->style = primitiveValueCache()->createIdentifierValue(CSSValueNormal);
   3753     if (!font->variant)
   3754         font->variant = primitiveValueCache()->createIdentifierValue(CSSValueNormal);
   3755     if (!font->weight)
   3756         font->weight = primitiveValueCache()->createIdentifierValue(CSSValueNormal);
   3757 
   3758     // now a font size _must_ come
   3759     // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
   3760     if (value->id >= CSSValueXxSmall && value->id <= CSSValueLarger)
   3761         font->size = primitiveValueCache()->createIdentifierValue(value->id);
   3762     else if (validUnit(value, FLength | FPercent | FNonNeg, m_strict))
   3763         font->size = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
   3764     value = m_valueList->next();
   3765     if (!font->size || !value)
   3766         return false;
   3767 
   3768     if (value->unit == CSSParserValue::Operator && value->iValue == '/') {
   3769         // line-height
   3770         value = m_valueList->next();
   3771         if (!value)
   3772             return false;
   3773         if (value->id == CSSValueNormal) {
   3774             // default value, nothing to do
   3775         } else if (validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict))
   3776             font->lineHeight = primitiveValueCache()->createValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
   3777         else
   3778             return false;
   3779         value = m_valueList->next();
   3780         if (!value)
   3781             return false;
   3782     }
   3783 
   3784     if (!font->lineHeight)
   3785         font->lineHeight = primitiveValueCache()->createIdentifierValue(CSSValueNormal);
   3786 
   3787     // font family must come now
   3788     font->family = parseFontFamily();
   3789 
   3790     if (m_valueList->current() || !font->family)
   3791         return false;
   3792 
   3793     addProperty(CSSPropertyFont, font.release(), important);
   3794     return true;
   3795 }
   3796 
   3797 PassRefPtr<CSSValueList> CSSParser::parseFontFamily()
   3798 {
   3799     RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
   3800     CSSParserValue* value = m_valueList->current();
   3801 
   3802     FontFamilyValue* currFamily = 0;
   3803     while (value) {
   3804         CSSParserValue* nextValue = m_valueList->next();
   3805         bool nextValBreaksFont = !nextValue ||
   3806                                  (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
   3807         bool nextValIsFontName = nextValue &&
   3808             ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
   3809             (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
   3810 
   3811         if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
   3812             if (currFamily)
   3813                 currFamily->appendSpaceSeparated(value->string.characters, value->string.length);
   3814             else if (nextValBreaksFont || !nextValIsFontName)
   3815                 list->append(primitiveValueCache()->createIdentifierValue(value->id));
   3816             else {
   3817                 RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string);
   3818                 currFamily = newFamily.get();
   3819                 list->append(newFamily.release());
   3820             }
   3821         } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
   3822             // Strings never share in a family name.
   3823             currFamily = 0;
   3824             list->append(FontFamilyValue::create(value->string));
   3825         } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
   3826             if (currFamily)
   3827                 currFamily->appendSpaceSeparated(value->string.characters, value->string.length);
   3828             else if (nextValBreaksFont || !nextValIsFontName)
   3829                 list->append(FontFamilyValue::create(value->string));
   3830             else {
   3831                 RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string);
   3832                 currFamily = newFamily.get();
   3833                 list->append(newFamily.release());
   3834             }
   3835         } else {
   3836             break;
   3837         }
   3838 
   3839         if (!nextValue)
   3840             break;
   3841 
   3842         if (nextValBreaksFont) {
   3843             value = m_valueList->next();
   3844             currFamily = 0;
   3845         }
   3846         else if (nextValIsFontName)
   3847             value = nextValue;
   3848         else
   3849             break;
   3850     }
   3851     if (!list->length())
   3852         list = 0;
   3853     return list.release();
   3854 }
   3855 
   3856 bool CSSParser::parseFontStyle(bool important)
   3857 {
   3858     RefPtr<CSSValueList> values;
   3859     if (m_valueList->size() > 1)
   3860         values = CSSValueList::createCommaSeparated();
   3861     CSSParserValue* val;
   3862     bool expectComma = false;
   3863     while ((val = m_valueList->current())) {
   3864         RefPtr<CSSPrimitiveValue> parsedValue;
   3865         if (!expectComma) {
   3866             expectComma = true;
   3867             if (val->id == CSSValueNormal || val->id == CSSValueItalic || val->id == CSSValueOblique)
   3868                 parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
   3869             else if (val->id == CSSValueAll && !values) {
   3870                 // 'all' is only allowed in @font-face and with no other values. Make a value list to
   3871                 // indicate that we are in the @font-face case.
   3872                 values = CSSValueList::createCommaSeparated();
   3873                 parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
   3874             }
   3875         } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   3876             expectComma = false;
   3877             m_valueList->next();
   3878             continue;
   3879         }
   3880 
   3881         if (!parsedValue)
   3882             return false;
   3883 
   3884         m_valueList->next();
   3885 
   3886         if (values)
   3887             values->append(parsedValue.release());
   3888         else {
   3889             addProperty(CSSPropertyFontStyle, parsedValue.release(), important);
   3890             return true;
   3891         }
   3892     }
   3893 
   3894     if (values && values->length()) {
   3895         m_hasFontFaceOnlyValues = true;
   3896         addProperty(CSSPropertyFontStyle, values.release(), important);
   3897         return true;
   3898     }
   3899 
   3900     return false;
   3901 }
   3902 
   3903 bool CSSParser::parseFontVariant(bool important)
   3904 {
   3905     RefPtr<CSSValueList> values;
   3906     if (m_valueList->size() > 1)
   3907         values = CSSValueList::createCommaSeparated();
   3908     CSSParserValue* val;
   3909     bool expectComma = false;
   3910     while ((val = m_valueList->current())) {
   3911         RefPtr<CSSPrimitiveValue> parsedValue;
   3912         if (!expectComma) {
   3913             expectComma = true;
   3914             if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
   3915                 parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
   3916             else if (val->id == CSSValueAll && !values) {
   3917                 // 'all' is only allowed in @font-face and with no other values. Make a value list to
   3918                 // indicate that we are in the @font-face case.
   3919                 values = CSSValueList::createCommaSeparated();
   3920                 parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
   3921             }
   3922         } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   3923             expectComma = false;
   3924             m_valueList->next();
   3925             continue;
   3926         }
   3927 
   3928         if (!parsedValue)
   3929             return false;
   3930 
   3931         m_valueList->next();
   3932 
   3933         if (values)
   3934             values->append(parsedValue.release());
   3935         else {
   3936             addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
   3937             return true;
   3938         }
   3939     }
   3940 
   3941     if (values && values->length()) {
   3942         m_hasFontFaceOnlyValues = true;
   3943         addProperty(CSSPropertyFontVariant, values.release(), important);
   3944         return true;
   3945     }
   3946 
   3947     return false;
   3948 }
   3949 
   3950 bool CSSParser::parseFontWeight(bool important)
   3951 {
   3952     RefPtr<CSSValueList> values;
   3953     if (m_valueList->size() > 1)
   3954         values = CSSValueList::createCommaSeparated();
   3955     CSSParserValue* val;
   3956     bool expectComma = false;
   3957     while ((val = m_valueList->current())) {
   3958         RefPtr<CSSPrimitiveValue> parsedValue;
   3959         if (!expectComma) {
   3960             expectComma = true;
   3961             if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
   3962                 if (val->id >= CSSValueNormal && val->id <= CSSValue900)
   3963                     parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
   3964                 else if (val->id == CSSValueAll && !values) {
   3965                     // 'all' is only allowed in @font-face and with no other values. Make a value list to
   3966                     // indicate that we are in the @font-face case.
   3967                     values = CSSValueList::createCommaSeparated();
   3968                     parsedValue = primitiveValueCache()->createIdentifierValue(val->id);
   3969                 }
   3970             } else if (validUnit(val, FInteger | FNonNeg, false)) {
   3971                 int weight = static_cast<int>(val->fValue);
   3972                 if (!(weight % 100) && weight >= 100 && weight <= 900)
   3973                     parsedValue = primitiveValueCache()->createIdentifierValue(CSSValue100 + weight / 100 - 1);
   3974             }
   3975         } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   3976             expectComma = false;
   3977             m_valueList->next();
   3978             continue;
   3979         }
   3980 
   3981         if (!parsedValue)
   3982             return false;
   3983 
   3984         m_valueList->next();
   3985 
   3986         if (values)
   3987             values->append(parsedValue.release());
   3988         else {
   3989             addProperty(CSSPropertyFontWeight, parsedValue.release(), important);
   3990             return true;
   3991         }
   3992     }
   3993 
   3994     if (values && values->length()) {
   3995         m_hasFontFaceOnlyValues = true;
   3996         addProperty(CSSPropertyFontWeight, values.release(), important);
   3997         return true;
   3998     }
   3999 
   4000     return false;
   4001 }
   4002 
   4003 static bool isValidFormatFunction(CSSParserValue* val)
   4004 {
   4005     CSSParserValueList* args = val->function->args.get();
   4006     return equalIgnoringCase(val->function->name, "format(") && (args->current()->unit == CSSPrimitiveValue::CSS_STRING || args->current()->unit == CSSPrimitiveValue::CSS_IDENT);
   4007 }
   4008 
   4009 bool CSSParser::parseFontFaceSrc()
   4010 {
   4011     RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
   4012     CSSParserValue* val;
   4013     bool expectComma = false;
   4014     bool allowFormat = false;
   4015     bool failed = false;
   4016     RefPtr<CSSFontFaceSrcValue> uriValue;
   4017     while ((val = m_valueList->current())) {
   4018         RefPtr<CSSFontFaceSrcValue> parsedValue;
   4019         if (val->unit == CSSPrimitiveValue::CSS_URI && !expectComma && m_styleSheet) {
   4020             // FIXME: The completeURL call should be done when using the CSSFontFaceSrcValue,
   4021             // not when creating it.
   4022             parsedValue = CSSFontFaceSrcValue::create(m_styleSheet->completeURL(val->string));
   4023             uriValue = parsedValue;
   4024             allowFormat = true;
   4025             expectComma = true;
   4026         } else if (val->unit == CSSParserValue::Function) {
   4027             // There are two allowed functions: local() and format().
   4028             CSSParserValueList* args = val->function->args.get();
   4029             if (args && args->size() == 1) {
   4030                 if (equalIgnoringCase(val->function->name, "local(") && !expectComma && (args->current()->unit == CSSPrimitiveValue::CSS_STRING || args->current()->unit == CSSPrimitiveValue::CSS_IDENT)) {
   4031                     expectComma = true;
   4032                     allowFormat = false;
   4033                     CSSParserValue* a = args->current();
   4034                     uriValue.clear();
   4035                     parsedValue = CSSFontFaceSrcValue::createLocal(a->string);
   4036                 } else if (allowFormat && uriValue && isValidFormatFunction(val)) {
   4037                     expectComma = true;
   4038                     allowFormat = false;
   4039                     uriValue->setFormat(args->current()->string);
   4040                     uriValue.clear();
   4041                     m_valueList->next();
   4042                     continue;
   4043                 }
   4044             }
   4045         } else if (val->unit == CSSParserValue::Operator && val->iValue == ',' && expectComma) {
   4046             expectComma = false;
   4047             allowFormat = false;
   4048             uriValue.clear();
   4049             m_valueList->next();
   4050             continue;
   4051         }
   4052 
   4053         if (parsedValue)
   4054             values->append(parsedValue.release());
   4055         else {
   4056             failed = true;
   4057             break;
   4058         }
   4059         m_valueList->next();
   4060     }
   4061 
   4062     if (values->length() && !failed) {
   4063         addProperty(CSSPropertySrc, values.release(), m_important);
   4064         m_valueList->next();
   4065         return true;
   4066     }
   4067 
   4068     return false;
   4069 }
   4070 
   4071 bool CSSParser::parseFontFaceUnicodeRange()
   4072 {
   4073     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
   4074     bool failed = false;
   4075     bool operatorExpected = false;
   4076     for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
   4077         if (operatorExpected) {
   4078             if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
   4079                 continue;
   4080             failed = true;
   4081             break;
   4082         }
   4083         if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
   4084             failed = true;
   4085             break;
   4086         }
   4087 
   4088         String rangeString = m_valueList->current()->string;
   4089         UChar32 from = 0;
   4090         UChar32 to = 0;
   4091         unsigned length = rangeString.length();
   4092 
   4093         if (length < 3) {
   4094             failed = true;
   4095             break;
   4096         }
   4097 
   4098         unsigned i = 2;
   4099         while (i < length) {
   4100             UChar c = rangeString[i];
   4101             if (c == '-' || c == '?')
   4102                 break;
   4103             from *= 16;
   4104             if (c >= '0' && c <= '9')
   4105                 from += c - '0';
   4106             else if (c >= 'A' && c <= 'F')
   4107                 from += 10 + c - 'A';
   4108             else if (c >= 'a' && c <= 'f')
   4109                 from += 10 + c - 'a';
   4110             else {
   4111                 failed = true;
   4112                 break;
   4113             }
   4114             i++;
   4115         }
   4116         if (failed)
   4117             break;
   4118 
   4119         if (i == length)
   4120             to = from;
   4121         else if (rangeString[i] == '?') {
   4122             unsigned span = 1;
   4123             while (i < length && rangeString[i] == '?') {
   4124                 span *= 16;
   4125                 from *= 16;
   4126                 i++;
   4127             }
   4128             if (i < length)
   4129                 failed = true;
   4130             to = from + span - 1;
   4131         } else {
   4132             if (length < i + 2) {
   4133                 failed = true;
   4134                 break;
   4135             }
   4136             i++;
   4137             while (i < length) {
   4138                 UChar c = rangeString[i];
   4139                 to *= 16;
   4140                 if (c >= '0' && c <= '9')
   4141                     to += c - '0';
   4142                 else if (c >= 'A' && c <= 'F')
   4143                     to += 10 + c - 'A';
   4144                 else if (c >= 'a' && c <= 'f')
   4145                     to += 10 + c - 'a';
   4146                 else {
   4147                     failed = true;
   4148                     break;
   4149                 }
   4150                 i++;
   4151             }
   4152             if (failed)
   4153                 break;
   4154         }
   4155         if (from <= to)
   4156             values->append(CSSUnicodeRangeValue::create(from, to));
   4157     }
   4158     if (failed || !values->length())
   4159         return false;
   4160     addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
   4161     return true;
   4162 }
   4163 
   4164 // Returns the number of characters which form a valid double
   4165 // and are terminated by the given terminator character
   4166 static int checkForValidDouble(const UChar* string, const UChar* end, const char terminator)
   4167 {
   4168     int length = end - string;
   4169     if (length < 1)
   4170         return 0;
   4171 
   4172     bool decimalMarkSeen = false;
   4173     int processedLength = 0;
   4174 
   4175     for (int i = 0; i < length; ++i) {
   4176         if (string[i] == terminator) {
   4177             processedLength = i;
   4178             break;
   4179         }
   4180         if (!isASCIIDigit(string[i])) {
   4181             if (!decimalMarkSeen && string[i] == '.')
   4182                 decimalMarkSeen = true;
   4183             else
   4184                 return 0;
   4185         }
   4186     }
   4187 
   4188     if (decimalMarkSeen && processedLength == 1)
   4189         return 0;
   4190 
   4191     return processedLength;
   4192 }
   4193 
   4194 // Returns the number of characters consumed for parsing a valid double
   4195 // terminated by the given terminator character
   4196 static int parseDouble(const UChar* string, const UChar* end, const char terminator, double& value)
   4197 {
   4198     int length = checkForValidDouble(string, end, terminator);
   4199     if (!length)
   4200         return 0;
   4201 
   4202     int position = 0;
   4203     double localValue = 0;
   4204 
   4205     // The consumed characters here are guaranteed to be
   4206     // ASCII digits with or without a decimal mark
   4207     for (; position < length; ++position) {
   4208         if (string[position] == '.')
   4209             break;
   4210         localValue = localValue * 10 + string[position] - '0';
   4211     }
   4212 
   4213     if (++position == length) {
   4214         value = localValue;
   4215         return length;
   4216     }
   4217 
   4218     double fraction = 0;
   4219     double scale = 1;
   4220 
   4221     while (position < length && scale < MAX_SCALE) {
   4222         fraction = fraction * 10 + string[position++] - '0';
   4223         scale *= 10;
   4224     }
   4225 
   4226     value = localValue + fraction / scale;
   4227     return length;
   4228 }
   4229 
   4230 static bool parseColorIntOrPercentage(const UChar*& string, const UChar* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
   4231 {
   4232     const UChar* current = string;
   4233     double localValue = 0;
   4234     bool negative = false;
   4235     while (current != end && isHTMLSpace(*current))
   4236         current++;
   4237     if (current != end && *current == '-') {
   4238         negative = true;
   4239         current++;
   4240     }
   4241     if (current == end || !isASCIIDigit(*current))
   4242         return false;
   4243     while (current != end && isASCIIDigit(*current)) {
   4244         double newValue = localValue * 10 + *current++ - '0';
   4245         if (newValue >= 255) {
   4246             // Clamp values at 255.
   4247             localValue = 255;
   4248             while (current != end && isASCIIDigit(*current))
   4249                 ++current;
   4250             break;
   4251         }
   4252         localValue = newValue;
   4253     }
   4254 
   4255     if (current == end)
   4256         return false;
   4257 
   4258     if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
   4259         return false;
   4260 
   4261     if (*current == '.') {
   4262         // We already parsed the integral part, try to parse
   4263         // the fraction part of the percentage value.
   4264         double percentage = 0;
   4265         int numCharactersParsed = parseDouble(current, end, '%', percentage);
   4266         if (!numCharactersParsed)
   4267             return false;
   4268         current += numCharactersParsed;
   4269         if (*current != '%')
   4270             return false;
   4271         localValue += percentage;
   4272     }
   4273 
   4274     if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
   4275         return false;
   4276 
   4277     if (*current == '%') {
   4278         expect = CSSPrimitiveValue::CSS_PERCENTAGE;
   4279         localValue = localValue / 100.0 * 256.0;
   4280         // Clamp values at 255 for percentages over 100%
   4281         if (localValue > 255)
   4282             localValue = 255;
   4283         current++;
   4284     } else
   4285         expect = CSSPrimitiveValue::CSS_NUMBER;
   4286 
   4287     while (current != end && isHTMLSpace(*current))
   4288         current++;
   4289     if (current == end || *current++ != terminator)
   4290         return false;
   4291     // Clamp negative values at zero.
   4292     value = negative ? 0 : static_cast<int>(localValue);
   4293     string = current;
   4294     return true;
   4295 }
   4296 
   4297 static inline bool isTenthAlpha(const UChar* string, const int length)
   4298 {
   4299     // "0.X"
   4300     if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
   4301         return true;
   4302 
   4303     // ".X"
   4304     if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
   4305         return true;
   4306 
   4307     return false;
   4308 }
   4309 
   4310 static inline bool parseAlphaValue(const UChar*& string, const UChar* end, const char terminator, int& value)
   4311 {
   4312     while (string != end && isHTMLSpace(*string))
   4313         string++;
   4314 
   4315     bool negative = false;
   4316 
   4317     if (string != end && *string == '-') {
   4318         negative = true;
   4319         string++;
   4320     }
   4321 
   4322     value = 0;
   4323 
   4324     int length = end - string;
   4325     if (length < 2)
   4326         return false;
   4327 
   4328     if (string[length - 1] != terminator)
   4329         return false;
   4330 
   4331     if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
   4332         if (checkForValidDouble(string, end, terminator)) {
   4333             value = negative ? 0 : 255;
   4334             string = end;
   4335             return true;
   4336         }
   4337         return false;
   4338     }
   4339 
   4340     if (length == 2 && string[0] != '.') {
   4341         value = !negative && string[0] == '1' ? 255 : 0;
   4342         string = end;
   4343         return true;
   4344     }
   4345 
   4346     if (isTenthAlpha(string, length - 1)) {
   4347         static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
   4348         value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
   4349         string = end;
   4350         return true;
   4351     }
   4352 
   4353     double alpha = 0;
   4354     if (!parseDouble(string, end, terminator, alpha))
   4355         return false;
   4356     value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
   4357     string = end;
   4358     return true;
   4359 }
   4360 
   4361 static inline bool mightBeRGBA(const UChar* characters, unsigned length)
   4362 {
   4363     if (length < 5)
   4364         return false;
   4365     return characters[4] == '('
   4366         && (characters[0] | 0x20) == 'r'
   4367         && (characters[1] | 0x20) == 'g'
   4368         && (characters[2] | 0x20) == 'b'
   4369         && (characters[3] | 0x20) == 'a';
   4370 }
   4371 
   4372 static inline bool mightBeRGB(const UChar* characters, unsigned length)
   4373 {
   4374     if (length < 4)
   4375         return false;
   4376     return characters[3] == '('
   4377         && (characters[0] | 0x20) == 'r'
   4378         && (characters[1] | 0x20) == 'g'
   4379         && (characters[2] | 0x20) == 'b';
   4380 }
   4381 
   4382 bool CSSParser::parseColor(const String &name, RGBA32& rgb, bool strict)
   4383 {
   4384     const UChar* characters = name.characters();
   4385     unsigned length = name.length();
   4386     CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
   4387 
   4388     if (!strict && length >= 3) {
   4389         if (name[0] == '#') {
   4390             if (Color::parseHexColor(characters + 1, length - 1, rgb))
   4391                 return true;
   4392         } else {
   4393             if (Color::parseHexColor(characters, length, rgb))
   4394                 return true;
   4395         }
   4396     }
   4397 
   4398     // Try rgba() syntax.
   4399     if (mightBeRGBA(characters, length)) {
   4400         const UChar* current = characters + 5;
   4401         const UChar* end = characters + length;
   4402         int red;
   4403         int green;
   4404         int blue;
   4405         int alpha;
   4406 
   4407         if (!parseColorIntOrPercentage(current, end, ',', expect, red))
   4408             return false;
   4409         if (!parseColorIntOrPercentage(current, end, ',', expect, green))
   4410             return false;
   4411         if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
   4412             return false;
   4413         if (!parseAlphaValue(current, end, ')', alpha))
   4414             return false;
   4415         if (current != end)
   4416             return false;
   4417         rgb = makeRGBA(red, green, blue, alpha);
   4418         return true;
   4419     }
   4420 
   4421     // Try rgb() syntax.
   4422     if (mightBeRGB(characters, length)) {
   4423         const UChar* current = characters + 4;
   4424         const UChar* end = characters + length;
   4425         int red;
   4426         int green;
   4427         int blue;
   4428         if (!parseColorIntOrPercentage(current, end, ',', expect, red))
   4429             return false;
   4430         if (!parseColorIntOrPercentage(current, end, ',', expect, green))
   4431             return false;
   4432         if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
   4433             return false;
   4434         if (current != end)
   4435             return false;
   4436         rgb = makeRGB(red, green, blue);
   4437         return true;
   4438     }
   4439 
   4440     // Try named colors.
   4441     Color tc;
   4442     tc.setNamedColor(name);
   4443     if (tc.isValid()) {
   4444         rgb = tc.rgb();
   4445         return true;
   4446     }
   4447     return false;
   4448 }
   4449 
   4450 static inline int colorIntFromValue(CSSParserValue* v)
   4451 {
   4452     if (v->fValue <= 0.0)
   4453         return 0;
   4454 
   4455     if (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE) {
   4456         if (v->fValue >= 100.0)
   4457             return 255;
   4458         return static_cast<int>(v->fValue * 256.0 / 100.0);
   4459     }
   4460 
   4461     if (v->fValue >= 255.0)
   4462         return 255;
   4463 
   4464     return static_cast<int>(v->fValue);
   4465 }
   4466 
   4467 bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
   4468 {
   4469     CSSParserValueList* args = value->function->args.get();
   4470     CSSParserValue* v = args->current();
   4471     Units unitType = FUnknown;
   4472     // Get the first value and its type
   4473     if (validUnit(v, FInteger, true))
   4474         unitType = FInteger;
   4475     else if (validUnit(v, FPercent, true))
   4476         unitType = FPercent;
   4477     else
   4478         return false;
   4479     colorArray[0] = colorIntFromValue(v);
   4480     for (int i = 1; i < 3; i++) {
   4481         v = args->next();
   4482         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   4483             return false;
   4484         v = args->next();
   4485         if (!validUnit(v, unitType, true))
   4486             return false;
   4487         colorArray[i] = colorIntFromValue(v);
   4488     }
   4489     if (parseAlpha) {
   4490         v = args->next();
   4491         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   4492             return false;
   4493         v = args->next();
   4494         if (!validUnit(v, FNumber, true))
   4495             return false;
   4496         // Convert the floating pointer number of alpha to an integer in the range [0, 256),
   4497         // with an equal distribution across all 256 values.
   4498         colorArray[3] = static_cast<int>(max(0.0, min(1.0, v->fValue)) * nextafter(256.0, 0.0));
   4499     }
   4500     return true;
   4501 }
   4502 
   4503 // The CSS3 specification defines the format of a HSL color as
   4504 // hsl(<number>, <percent>, <percent>)
   4505 // and with alpha, the format is
   4506 // hsla(<number>, <percent>, <percent>, <number>)
   4507 // The first value, HUE, is in an angle with a value between 0 and 360
   4508 bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
   4509 {
   4510     CSSParserValueList* args = value->function->args.get();
   4511     CSSParserValue* v = args->current();
   4512     // Get the first value
   4513     if (!validUnit(v, FNumber, true))
   4514         return false;
   4515     // normalize the Hue value and change it to be between 0 and 1.0
   4516     colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
   4517     for (int i = 1; i < 3; i++) {
   4518         v = args->next();
   4519         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   4520             return false;
   4521         v = args->next();
   4522         if (!validUnit(v, FPercent, true))
   4523             return false;
   4524         colorArray[i] = max(0.0, min(100.0, v->fValue)) / 100.0; // needs to be value between 0 and 1.0
   4525     }
   4526     if (parseAlpha) {
   4527         v = args->next();
   4528         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   4529             return false;
   4530         v = args->next();
   4531         if (!validUnit(v, FNumber, true))
   4532             return false;
   4533         colorArray[3] = max(0.0, min(1.0, v->fValue));
   4534     }
   4535     return true;
   4536 }
   4537 
   4538 PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value)
   4539 {
   4540     RGBA32 c = Color::transparent;
   4541     if (!parseColorFromValue(value ? value : m_valueList->current(), c))
   4542         return 0;
   4543     return primitiveValueCache()->createColorValue(c);
   4544 }
   4545 
   4546 bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
   4547 {
   4548     if (!m_strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
   4549         value->fValue >= 0. && value->fValue < 1000000.) {
   4550         String str = String::format("%06d", (int)(value->fValue+.5));
   4551         if (!CSSParser::parseColor(str, c, m_strict))
   4552             return false;
   4553     } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
   4554                 value->unit == CSSPrimitiveValue::CSS_IDENT ||
   4555                 (!m_strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
   4556         if (!CSSParser::parseColor(value->string, c, m_strict && value->unit == CSSPrimitiveValue::CSS_IDENT))
   4557             return false;
   4558     } else if (value->unit == CSSParserValue::Function &&
   4559                 value->function->args != 0 &&
   4560                 value->function->args->size() == 5 /* rgb + two commas */ &&
   4561                 equalIgnoringCase(value->function->name, "rgb(")) {
   4562         int colorValues[3];
   4563         if (!parseColorParameters(value, colorValues, false))
   4564             return false;
   4565         c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
   4566     } else {
   4567         if (value->unit == CSSParserValue::Function &&
   4568                 value->function->args != 0 &&
   4569                 value->function->args->size() == 7 /* rgba + three commas */ &&
   4570                 equalIgnoringCase(value->function->name, "rgba(")) {
   4571             int colorValues[4];
   4572             if (!parseColorParameters(value, colorValues, true))
   4573                 return false;
   4574             c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
   4575         } else if (value->unit == CSSParserValue::Function &&
   4576                     value->function->args != 0 &&
   4577                     value->function->args->size() == 5 /* hsl + two commas */ &&
   4578                     equalIgnoringCase(value->function->name, "hsl(")) {
   4579             double colorValues[3];
   4580             if (!parseHSLParameters(value, colorValues, false))
   4581                 return false;
   4582             c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
   4583         } else if (value->unit == CSSParserValue::Function &&
   4584                     value->function->args != 0 &&
   4585                     value->function->args->size() == 7 /* hsla + three commas */ &&
   4586                     equalIgnoringCase(value->function->name, "hsla(")) {
   4587             double colorValues[4];
   4588             if (!parseHSLParameters(value, colorValues, true))
   4589                 return false;
   4590             c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
   4591         } else
   4592             return false;
   4593     }
   4594 
   4595     return true;
   4596 }
   4597 
   4598 // This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
   4599 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
   4600 struct ShadowParseContext {
   4601     ShadowParseContext(CSSPropertyID prop, CSSPrimitiveValueCache* primitiveValueCache)
   4602         : property(prop)
   4603         , m_primitiveValueCache(primitiveValueCache)
   4604         , allowX(true)
   4605         , allowY(false)
   4606         , allowBlur(false)
   4607         , allowSpread(false)
   4608         , allowColor(true)
   4609         , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
   4610         , allowBreak(true)
   4611     {
   4612     }
   4613 
   4614     bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
   4615 
   4616     void commitValue()
   4617     {
   4618         // Handle the ,, case gracefully by doing nothing.
   4619         if (x || y || blur || spread || color || style) {
   4620             if (!values)
   4621                 values = CSSValueList::createCommaSeparated();
   4622 
   4623             // Construct the current shadow value and add it to the list.
   4624             values->append(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
   4625         }
   4626 
   4627         // Now reset for the next shadow value.
   4628         x = 0;
   4629         y = 0;
   4630         blur = 0;
   4631         spread = 0;
   4632         style = 0;
   4633         color = 0;
   4634 
   4635         allowX = true;
   4636         allowColor = true;
   4637         allowBreak = true;
   4638         allowY = false;
   4639         allowBlur = false;
   4640         allowSpread = false;
   4641         allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
   4642     }
   4643 
   4644     void commitLength(CSSParserValue* v)
   4645     {
   4646         RefPtr<CSSPrimitiveValue> val = m_primitiveValueCache->createValue(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit);
   4647 
   4648         if (allowX) {
   4649             x = val.release();
   4650             allowX = false;
   4651             allowY = true;
   4652             allowColor = false;
   4653             allowStyle = false;
   4654             allowBreak = false;
   4655         } else if (allowY) {
   4656             y = val.release();
   4657             allowY = false;
   4658             allowBlur = true;
   4659             allowColor = true;
   4660             allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
   4661             allowBreak = true;
   4662         } else if (allowBlur) {
   4663             blur = val.release();
   4664             allowBlur = false;
   4665             allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
   4666         } else if (allowSpread) {
   4667             spread = val.release();
   4668             allowSpread = false;
   4669         }
   4670     }
   4671 
   4672     void commitColor(PassRefPtr<CSSPrimitiveValue> val)
   4673     {
   4674         color = val;
   4675         allowColor = false;
   4676         if (allowX) {
   4677             allowStyle = false;
   4678             allowBreak = false;
   4679         } else {
   4680             allowBlur = false;
   4681             allowSpread = false;
   4682             allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
   4683         }
   4684     }
   4685 
   4686     void commitStyle(CSSParserValue* v)
   4687     {
   4688         style = m_primitiveValueCache->createIdentifierValue(v->id);
   4689         allowStyle = false;
   4690         if (allowX)
   4691             allowBreak = false;
   4692         else {
   4693             allowBlur = false;
   4694             allowSpread = false;
   4695             allowColor = false;
   4696         }
   4697     }
   4698 
   4699     CSSPropertyID property;
   4700     CSSPrimitiveValueCache* m_primitiveValueCache;
   4701 
   4702     RefPtr<CSSValueList> values;
   4703     RefPtr<CSSPrimitiveValue> x;
   4704     RefPtr<CSSPrimitiveValue> y;
   4705     RefPtr<CSSPrimitiveValue> blur;
   4706     RefPtr<CSSPrimitiveValue> spread;
   4707     RefPtr<CSSPrimitiveValue> style;
   4708     RefPtr<CSSPrimitiveValue> color;
   4709 
   4710     bool allowX;
   4711     bool allowY;
   4712     bool allowBlur;
   4713     bool allowSpread;
   4714     bool allowColor;
   4715     bool allowStyle; // inset or not.
   4716     bool allowBreak;
   4717 };
   4718 
   4719 bool CSSParser::parseShadow(int propId, bool important)
   4720 {
   4721     ShadowParseContext context(static_cast<CSSPropertyID>(propId), primitiveValueCache());
   4722     CSSParserValue* val;
   4723     while ((val = m_valueList->current())) {
   4724         // Check for a comma break first.
   4725         if (val->unit == CSSParserValue::Operator) {
   4726             if (val->iValue != ',' || !context.allowBreak)
   4727                 // Other operators aren't legal or we aren't done with the current shadow
   4728                 // value.  Treat as invalid.
   4729                 return false;
   4730 #if ENABLE(SVG)
   4731             // -webkit-svg-shadow does not support multiple values.
   4732             if (static_cast<CSSPropertyID>(propId) == CSSPropertyWebkitSvgShadow)
   4733                 return false;
   4734 #endif
   4735             // The value is good.  Commit it.
   4736             context.commitValue();
   4737         } else if (validUnit(val, FLength, true)) {
   4738             // We required a length and didn't get one. Invalid.
   4739             if (!context.allowLength())
   4740                 return false;
   4741 
   4742             // A length is allowed here.  Construct the value and add it.
   4743             context.commitLength(val);
   4744         } else if (val->id == CSSValueInset) {
   4745             if (!context.allowStyle)
   4746                 return false;
   4747 
   4748             context.commitStyle(val);
   4749         } else {
   4750             // The only other type of value that's ok is a color value.
   4751             RefPtr<CSSPrimitiveValue> parsedColor;
   4752             bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu ||
   4753                             (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && !m_strict));
   4754             if (isColor) {
   4755                 if (!context.allowColor)
   4756                     return false;
   4757                 parsedColor = primitiveValueCache()->createIdentifierValue(val->id);
   4758             }
   4759 
   4760             if (!parsedColor)
   4761                 // It's not built-in. Try to parse it as a color.
   4762                 parsedColor = parseColor(val);
   4763 
   4764             if (!parsedColor || !context.allowColor)
   4765                 return false; // This value is not a color or length and is invalid or
   4766                               // it is a color, but a color isn't allowed at this point.
   4767 
   4768             context.commitColor(parsedColor.release());
   4769         }
   4770 
   4771         m_valueList->next();
   4772     }
   4773 
   4774     if (context.allowBreak) {
   4775         context.commitValue();
   4776         if (context.values->length()) {
   4777             addProperty(propId, context.values.release(), important);
   4778             m_valueList->next();
   4779             return true;
   4780         }
   4781     }
   4782 
   4783     return false;
   4784 }
   4785 
   4786 bool CSSParser::parseReflect(int propId, bool important)
   4787 {
   4788     // box-reflect: <direction> <offset> <mask>
   4789 
   4790     // Direction comes first.
   4791     CSSParserValue* val = m_valueList->current();
   4792     CSSReflectionDirection direction;
   4793     switch (val->id) {
   4794         case CSSValueAbove:
   4795             direction = ReflectionAbove;
   4796             break;
   4797         case CSSValueBelow:
   4798             direction = ReflectionBelow;
   4799             break;
   4800         case CSSValueLeft:
   4801             direction = ReflectionLeft;
   4802             break;
   4803         case CSSValueRight:
   4804             direction = ReflectionRight;
   4805             break;
   4806         default:
   4807             return false;
   4808     }
   4809 
   4810     // The offset comes next.
   4811     val = m_valueList->next();
   4812     RefPtr<CSSPrimitiveValue> offset;
   4813     if (!val)
   4814         offset = primitiveValueCache()->createValue(0, CSSPrimitiveValue::CSS_PX);
   4815     else {
   4816         if (!validUnit(val, FLength | FPercent, m_strict))
   4817             return false;
   4818         offset = primitiveValueCache()->createValue(val->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(val->unit));
   4819     }
   4820 
   4821     // Now for the mask.
   4822     RefPtr<CSSValue> mask;
   4823     val = m_valueList->next();
   4824     if (val) {
   4825         if (!parseBorderImage(propId, important, mask))
   4826             return false;
   4827     }
   4828 
   4829     RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction, offset.release(), mask.release());
   4830     addProperty(propId, reflectValue.release(), important);
   4831     m_valueList->next();
   4832     return true;
   4833 }
   4834 
   4835 struct BorderImageParseContext {
   4836     BorderImageParseContext(CSSPrimitiveValueCache* primitiveValueCache)
   4837     : m_primitiveValueCache(primitiveValueCache)
   4838     , m_allowBreak(false)
   4839     , m_allowNumber(false)
   4840     , m_allowSlash(false)
   4841     , m_allowWidth(false)
   4842     , m_allowRule(false)
   4843     , m_borderTop(0)
   4844     , m_borderRight(0)
   4845     , m_borderBottom(0)
   4846     , m_borderLeft(0)
   4847     , m_horizontalRule(0)
   4848     , m_verticalRule(0)
   4849     {}
   4850 
   4851     bool allowBreak() const { return m_allowBreak; }
   4852     bool allowNumber() const { return m_allowNumber; }
   4853     bool allowSlash() const { return m_allowSlash; }
   4854     bool allowWidth() const { return m_allowWidth; }
   4855     bool allowRule() const { return m_allowRule; }
   4856 
   4857     void commitImage(PassRefPtr<CSSValue> image) { m_image = image; m_allowNumber = true; }
   4858     void commitNumber(CSSParserValue* v)
   4859     {
   4860         PassRefPtr<CSSPrimitiveValue> val = m_primitiveValueCache->createValue(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit);
   4861         if (!m_top)
   4862             m_top = val;
   4863         else if (!m_right)
   4864             m_right = val;
   4865         else if (!m_bottom)
   4866             m_bottom = val;
   4867         else {
   4868             ASSERT(!m_left);
   4869             m_left = val;
   4870         }
   4871 
   4872         m_allowBreak = m_allowSlash = m_allowRule = true;
   4873         m_allowNumber = !m_left;
   4874     }
   4875     void commitSlash() { m_allowBreak = m_allowSlash = m_allowNumber = false; m_allowWidth = true; }
   4876     void commitWidth(CSSParserValue* val)
   4877     {
   4878         if (!m_borderTop)
   4879             m_borderTop = val;
   4880         else if (!m_borderRight)
   4881             m_borderRight = val;
   4882         else if (!m_borderBottom)
   4883             m_borderBottom = val;
   4884         else {
   4885             ASSERT(!m_borderLeft);
   4886             m_borderLeft = val;
   4887         }
   4888 
   4889         m_allowBreak = m_allowRule = true;
   4890         m_allowWidth = !m_borderLeft;
   4891     }
   4892     void commitRule(int keyword)
   4893     {
   4894         if (!m_horizontalRule)
   4895             m_horizontalRule = keyword;
   4896         else if (!m_verticalRule)
   4897             m_verticalRule = keyword;
   4898         m_allowRule = !m_verticalRule;
   4899     }
   4900     PassRefPtr<CSSValue> commitBorderImage(CSSParser* p, bool important)
   4901     {
   4902         // We need to clone and repeat values for any omissions.
   4903         if (!m_right) {
   4904             m_right = m_primitiveValueCache->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
   4905             m_bottom = m_primitiveValueCache->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
   4906             m_left = m_primitiveValueCache->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
   4907         }
   4908         if (!m_bottom) {
   4909             m_bottom = m_primitiveValueCache->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
   4910             m_left = m_primitiveValueCache->createValue(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType());
   4911         }
   4912         if (!m_left)
   4913              m_left = m_primitiveValueCache->createValue(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType());
   4914 
   4915         // Now build a rect value to hold all four of our primitive values.
   4916         RefPtr<Rect> rect = Rect::create();
   4917         rect->setTop(m_top);
   4918         rect->setRight(m_right);
   4919         rect->setBottom(m_bottom);
   4920         rect->setLeft(m_left);
   4921 
   4922         // Fill in STRETCH as the default if it wasn't specified.
   4923         if (!m_horizontalRule)
   4924             m_horizontalRule = CSSValueStretch;
   4925 
   4926         // The vertical rule should match the horizontal rule if unspecified.
   4927         if (!m_verticalRule)
   4928             m_verticalRule = m_horizontalRule;
   4929 
   4930         // Now we have to deal with the border widths.  The best way to deal with these is to actually put these values into a value
   4931         // list and then make our parsing machinery do the parsing.
   4932         if (m_borderTop) {
   4933             CSSParserValueList newList;
   4934             newList.addValue(*m_borderTop);
   4935             if (m_borderRight)
   4936                 newList.addValue(*m_borderRight);
   4937             if (m_borderBottom)
   4938                 newList.addValue(*m_borderBottom);
   4939             if (m_borderLeft)
   4940                 newList.addValue(*m_borderLeft);
   4941             CSSParserValueList* oldList = p->m_valueList;
   4942             p->m_valueList = &newList;
   4943             p->parseValue(CSSPropertyBorderWidth, important);
   4944             p->m_valueList = oldList;
   4945         }
   4946 
   4947         // Make our new border image value now.
   4948         return CSSBorderImageValue::create(m_image, rect.release(), m_horizontalRule, m_verticalRule);
   4949     }
   4950 
   4951     CSSPrimitiveValueCache* m_primitiveValueCache;
   4952 
   4953     bool m_allowBreak;
   4954     bool m_allowNumber;
   4955     bool m_allowSlash;
   4956     bool m_allowWidth;
   4957     bool m_allowRule;
   4958 
   4959     RefPtr<CSSValue> m_image;
   4960 
   4961     RefPtr<CSSPrimitiveValue> m_top;
   4962     RefPtr<CSSPrimitiveValue> m_right;
   4963     RefPtr<CSSPrimitiveValue> m_bottom;
   4964     RefPtr<CSSPrimitiveValue> m_left;
   4965 
   4966     CSSParserValue* m_borderTop;
   4967     CSSParserValue* m_borderRight;
   4968     CSSParserValue* m_borderBottom;
   4969     CSSParserValue* m_borderLeft;
   4970 
   4971     int m_horizontalRule;
   4972     int m_verticalRule;
   4973 };
   4974 
   4975 bool CSSParser::parseBorderImage(int propId, bool important, RefPtr<CSSValue>& result)
   4976 {
   4977     // Look for an image initially.  If the first value is not a URI, then we're done.
   4978     BorderImageParseContext context(primitiveValueCache());
   4979     CSSParserValue* val = m_valueList->current();
   4980     if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
   4981         // FIXME: The completeURL call should be done when using the CSSImageValue,
   4982         // not when creating it.
   4983         context.commitImage(CSSImageValue::create(m_styleSheet->completeURL(val->string)));
   4984     } else if (isGeneratedImageValue(val)) {
   4985         RefPtr<CSSValue> value;
   4986         if (parseGeneratedImage(value))
   4987             context.commitImage(value);
   4988         else
   4989             return false;
   4990     } else
   4991         return false;
   4992 
   4993     while ((val = m_valueList->next())) {
   4994         if (context.allowNumber() && validUnit(val, FInteger | FNonNeg | FPercent, true)) {
   4995             context.commitNumber(val);
   4996         } else if (propId == CSSPropertyWebkitBorderImage && context.allowSlash() && val->unit == CSSParserValue::Operator && val->iValue == '/') {
   4997             context.commitSlash();
   4998         } else if (context.allowWidth() &&
   4999             (val->id == CSSValueThin || val->id == CSSValueMedium || val->id == CSSValueThick || validUnit(val, FLength, m_strict))) {
   5000             context.commitWidth(val);
   5001         } else if (context.allowRule() &&
   5002             (val->id == CSSValueStretch || val->id == CSSValueRound || val->id == CSSValueRepeat)) {
   5003             context.commitRule(val->id);
   5004         } else {
   5005             // Something invalid was encountered.
   5006             return false;
   5007         }
   5008     }
   5009 
   5010     if (context.allowNumber() && propId != CSSPropertyWebkitBorderImage) {
   5011         // Allow the slices to be omitted for images that don't fit to a border.  We just set the slices to be 0.
   5012         context.m_top = primitiveValueCache()->createValue(0, CSSPrimitiveValue::CSS_NUMBER);
   5013         context.m_allowBreak = true;
   5014     }
   5015 
   5016     if (context.allowBreak()) {
   5017         // Need to fully commit as a single value.
   5018         result = context.commitBorderImage(this, important);
   5019         return true;
   5020     }
   5021 
   5022     return false;
   5023 }
   5024 
   5025 static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4])
   5026 {
   5027     if (radii[3])
   5028         return;
   5029     if (!radii[2]) {
   5030         if (!radii[1])
   5031             radii[1] = radii[0];
   5032         radii[2] = radii[0];
   5033     }
   5034     radii[3] = radii[1];
   5035 }
   5036 
   5037 bool CSSParser::parseBorderRadius(int propId, bool important)
   5038 {
   5039     unsigned num = m_valueList->size();
   5040     if (num > 9)
   5041         return false;
   5042 
   5043     ShorthandScope scope(this, propId);
   5044     RefPtr<CSSPrimitiveValue> radii[2][4];
   5045 
   5046     unsigned indexAfterSlash = 0;
   5047     for (unsigned i = 0; i < num; ++i) {
   5048         CSSParserValue* value = m_valueList->valueAt(i);
   5049         if (value->unit == CSSParserValue::Operator) {
   5050             if (value->iValue != '/')
   5051                 return false;
   5052 
   5053             if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
   5054                 return false;
   5055 
   5056             indexAfterSlash = i + 1;
   5057             completeBorderRadii(radii[0]);
   5058             continue;
   5059         }
   5060 
   5061         if (i - indexAfterSlash >= 4)
   5062             return false;
   5063 
   5064         if (!validUnit(value, FLength | FPercent, m_strict))
   5065             return false;
   5066 
   5067         RefPtr<CSSPrimitiveValue> radius = primitiveValueCache()->createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
   5068 
   5069         if (!indexAfterSlash) {
   5070             radii[0][i] = radius;
   5071 
   5072             // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
   5073             if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
   5074                 indexAfterSlash = 1;
   5075                 completeBorderRadii(radii[0]);
   5076             }
   5077         } else
   5078             radii[1][i - indexAfterSlash] = radius.release();
   5079     }
   5080 
   5081     if (!indexAfterSlash) {
   5082         completeBorderRadii(radii[0]);
   5083         for (unsigned i = 0; i < 4; ++i)
   5084             radii[1][i] = radii[0][i];
   5085     } else
   5086         completeBorderRadii(radii[1]);
   5087 
   5088     m_implicitShorthand = true;
   5089     addProperty(CSSPropertyBorderTopLeftRadius, primitiveValueCache()->createValue(Pair::create(radii[0][0].release(), radii[1][0].release())), important);
   5090     addProperty(CSSPropertyBorderTopRightRadius, primitiveValueCache()->createValue(Pair::create(radii[0][1].release(), radii[1][1].release())), important);
   5091     addProperty(CSSPropertyBorderBottomRightRadius, primitiveValueCache()->createValue(Pair::create(radii[0][2].release(), radii[1][2].release())), important);
   5092     addProperty(CSSPropertyBorderBottomLeftRadius, primitiveValueCache()->createValue(Pair::create(radii[0][3].release(), radii[1][3].release())), important);
   5093     m_implicitShorthand = false;
   5094     return true;
   5095 }
   5096 
   5097 bool CSSParser::parseCounter(int propId, int defaultValue, bool important)
   5098 {
   5099     enum { ID, VAL } state = ID;
   5100 
   5101     RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
   5102     RefPtr<CSSPrimitiveValue> counterName;
   5103 
   5104     while (true) {
   5105         CSSParserValue* val = m_valueList->current();
   5106         switch (state) {
   5107             case ID:
   5108                 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
   5109                     counterName = primitiveValueCache()->createValue(val->string, CSSPrimitiveValue::CSS_STRING);
   5110                     state = VAL;
   5111                     m_valueList->next();
   5112                     continue;
   5113                 }
   5114                 break;
   5115             case VAL: {
   5116                 int i = defaultValue;
   5117                 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
   5118                     i = clampToInteger(val->fValue);
   5119                     m_valueList->next();
   5120                 }
   5121 
   5122                 list->append(primitiveValueCache()->createValue(Pair::create(counterName.release(),
   5123                     primitiveValueCache()->createValue(i, CSSPrimitiveValue::CSS_NUMBER))));
   5124                 state = ID;
   5125                 continue;
   5126             }
   5127         }
   5128         break;
   5129     }
   5130 
   5131     if (list->length() > 0) {
   5132         addProperty(propId, list.release(), important);
   5133         return true;
   5134     }
   5135 
   5136     return false;
   5137 }
   5138 
   5139 // This should go away once we drop support for -webkit-gradient
   5140 static PassRefPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal, CSSPrimitiveValueCache* primitiveValueCache)
   5141 {
   5142     RefPtr<CSSPrimitiveValue> result;
   5143     if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
   5144         if ((equalIgnoringCase(a->string, "left") && horizontal) ||
   5145             (equalIgnoringCase(a->string, "top") && !horizontal))
   5146             result = primitiveValueCache->createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
   5147         else if ((equalIgnoringCase(a->string, "right") && horizontal) ||
   5148                  (equalIgnoringCase(a->string, "bottom") && !horizontal))
   5149             result = primitiveValueCache->createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
   5150         else if (equalIgnoringCase(a->string, "center"))
   5151             result = primitiveValueCache->createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
   5152     } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
   5153         result = primitiveValueCache->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit);
   5154     return result;
   5155 }
   5156 
   5157 static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
   5158 {
   5159     if (a->unit != CSSParserValue::Function)
   5160         return false;
   5161 
   5162     if (!equalIgnoringCase(a->function->name, "from(") &&
   5163         !equalIgnoringCase(a->function->name, "to(") &&
   5164         !equalIgnoringCase(a->function->name, "color-stop("))
   5165         return false;
   5166 
   5167     CSSParserValueList* args = a->function->args.get();
   5168     if (!args)
   5169         return false;
   5170 
   5171     if (equalIgnoringCase(a->function->name, "from(") ||
   5172         equalIgnoringCase(a->function->name, "to(")) {
   5173         // The "from" and "to" stops expect 1 argument.
   5174         if (args->size() != 1)
   5175             return false;
   5176 
   5177         if (equalIgnoringCase(a->function->name, "from("))
   5178             stop.m_position = p->primitiveValueCache()->createValue(0, CSSPrimitiveValue::CSS_NUMBER);
   5179         else
   5180             stop.m_position = p->primitiveValueCache()->createValue(1, CSSPrimitiveValue::CSS_NUMBER);
   5181 
   5182         int id = args->current()->id;
   5183         if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
   5184             stop.m_color = p->primitiveValueCache()->createIdentifierValue(id);
   5185         else
   5186             stop.m_color = p->parseColor(args->current());
   5187         if (!stop.m_color)
   5188             return false;
   5189     }
   5190 
   5191     // The "color-stop" function expects 3 arguments.
   5192     if (equalIgnoringCase(a->function->name, "color-stop(")) {
   5193         if (args->size() != 3)
   5194             return false;
   5195 
   5196         CSSParserValue* stopArg = args->current();
   5197         if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
   5198             stop.m_position = p->primitiveValueCache()->createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
   5199         else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
   5200             stop.m_position = p->primitiveValueCache()->createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
   5201         else
   5202             return false;
   5203 
   5204         stopArg = args->next();
   5205         if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
   5206             return false;
   5207 
   5208         stopArg = args->next();
   5209         int id = stopArg->id;
   5210         if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
   5211             stop.m_color = p->primitiveValueCache()->createIdentifierValue(id);
   5212         else
   5213             stop.m_color = p->parseColor(stopArg);
   5214         if (!stop.m_color)
   5215             return false;
   5216     }
   5217 
   5218     return true;
   5219 }
   5220 
   5221 bool CSSParser::parseDeprecatedGradient(RefPtr<CSSValue>& gradient)
   5222 {
   5223     // Walk the arguments.
   5224     CSSParserValueList* args = m_valueList->current()->function->args.get();
   5225     if (!args || args->size() == 0)
   5226         return false;
   5227 
   5228     // The first argument is the gradient type.  It is an identifier.
   5229     CSSGradientType gradientType;
   5230     CSSParserValue* a = args->current();
   5231     if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
   5232         return false;
   5233     if (equalIgnoringCase(a->string, "linear"))
   5234         gradientType = CSSLinearGradient;
   5235     else if (equalIgnoringCase(a->string, "radial"))
   5236         gradientType = CSSRadialGradient;
   5237     else
   5238         return false;
   5239 
   5240     RefPtr<CSSGradientValue> result;
   5241     switch (gradientType) {
   5242         case CSSLinearGradient:
   5243             result = CSSLinearGradientValue::create(NonRepeating, true);
   5244             break;
   5245         case CSSRadialGradient:
   5246             result = CSSRadialGradientValue::create(NonRepeating, true);
   5247             break;
   5248     }
   5249 
   5250     // Comma.
   5251     a = args->next();
   5252     if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
   5253         return false;
   5254 
   5255     // Next comes the starting point for the gradient as an x y pair.  There is no
   5256     // comma between the x and the y values.
   5257     // First X.  It can be left, right, number or percent.
   5258     a = args->next();
   5259     if (!a)
   5260         return false;
   5261     RefPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true, primitiveValueCache());
   5262     if (!point)
   5263         return false;
   5264     result->setFirstX(point.release());
   5265 
   5266     // First Y.  It can be top, bottom, number or percent.
   5267     a = args->next();
   5268     if (!a)
   5269         return false;
   5270     point = parseDeprecatedGradientPoint(a, false, primitiveValueCache());
   5271     if (!point)
   5272         return false;
   5273     result->setFirstY(point.release());
   5274 
   5275     // Comma after the first point.
   5276     a = args->next();
   5277     if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
   5278         return false;
   5279 
   5280     // For radial gradients only, we now expect a numeric radius.
   5281     if (gradientType == CSSRadialGradient) {
   5282         a = args->next();
   5283         if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
   5284             return false;
   5285         static_cast<CSSRadialGradientValue*>(result.get())->setFirstRadius(primitiveValueCache()->createValue(a->fValue, CSSPrimitiveValue::CSS_NUMBER));
   5286 
   5287         // Comma after the first radius.
   5288         a = args->next();
   5289         if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
   5290             return false;
   5291     }
   5292 
   5293     // Next is the ending point for the gradient as an x, y pair.
   5294     // Second X.  It can be left, right, number or percent.
   5295     a = args->next();
   5296     if (!a)
   5297         return false;
   5298     point = parseDeprecatedGradientPoint(a, true, primitiveValueCache());
   5299     if (!point)
   5300         return false;
   5301     result->setSecondX(point.release());
   5302 
   5303     // Second Y.  It can be top, bottom, number or percent.
   5304     a = args->next();
   5305     if (!a)
   5306         return false;
   5307     point = parseDeprecatedGradientPoint(a, false, primitiveValueCache());
   5308     if (!point)
   5309         return false;
   5310     result->setSecondY(point.release());
   5311 
   5312     // For radial gradients only, we now expect the second radius.
   5313     if (gradientType == CSSRadialGradient) {
   5314         // Comma after the second point.
   5315         a = args->next();
   5316         if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',')
   5317             return false;
   5318 
   5319         a = args->next();
   5320         if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
   5321             return false;
   5322         static_cast<CSSRadialGradientValue*>(result.get())->setSecondRadius(primitiveValueCache()->createValue(a->fValue, CSSPrimitiveValue::CSS_NUMBER));
   5323     }
   5324 
   5325     // We now will accept any number of stops (0 or more).
   5326     a = args->next();
   5327     while (a) {
   5328         // Look for the comma before the next stop.
   5329         if (a->unit != CSSParserValue::Operator || a->iValue != ',')
   5330             return false;
   5331 
   5332         // Now examine the stop itself.
   5333         a = args->next();
   5334         if (!a)
   5335             return false;
   5336 
   5337         // The function name needs to be one of "from", "to", or "color-stop."
   5338         CSSGradientColorStop stop;
   5339         if (!parseDeprecatedGradientColorStop(this, a, stop))
   5340             return false;
   5341         result->addStop(stop);
   5342 
   5343         // Advance
   5344         a = args->next();
   5345     }
   5346 
   5347     gradient = result.release();
   5348     return true;
   5349 }
   5350 
   5351 static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal, CSSPrimitiveValueCache* primitiveValueCache)
   5352 {
   5353     if (a->unit != CSSPrimitiveValue::CSS_IDENT)
   5354         return 0;
   5355 
   5356     switch (a->id) {
   5357         case CSSValueLeft:
   5358         case CSSValueRight:
   5359             isHorizontal = true;
   5360             break;
   5361         case CSSValueTop:
   5362         case CSSValueBottom:
   5363             isHorizontal = false;
   5364             break;
   5365         default:
   5366             return 0;
   5367     }
   5368     return primitiveValueCache->createIdentifierValue(a->id);
   5369 }
   5370 
   5371 static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSParser* p, CSSParserValue* value)
   5372 {
   5373     int id = value->id;
   5374     if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
   5375         return p->primitiveValueCache()->createIdentifierValue(id);
   5376 
   5377     return p->parseColor(value);
   5378 }
   5379 
   5380 bool CSSParser::parseLinearGradient(RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
   5381 {
   5382     RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating);
   5383 
   5384     // Walk the arguments.
   5385     CSSParserValueList* args = m_valueList->current()->function->args.get();
   5386     if (!args || !args->size())
   5387         return false;
   5388 
   5389     CSSParserValue* a = args->current();
   5390     if (!a)
   5391         return false;
   5392 
   5393     bool expectComma = false;
   5394     // Look for angle.
   5395     if (validUnit(a, FAngle, true)) {
   5396         result->setAngle(primitiveValueCache()->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit));
   5397 
   5398         a = args->next();
   5399         expectComma = true;
   5400     } else {
   5401         // Look one or two optional keywords that indicate a side or corner.
   5402         RefPtr<CSSPrimitiveValue> startX, startY;
   5403 
   5404         RefPtr<CSSPrimitiveValue> location;
   5405         bool isHorizontal = false;
   5406         if ((location = valueFromSideKeyword(a, isHorizontal, primitiveValueCache()))) {
   5407             if (isHorizontal)
   5408                 startX = location;
   5409             else
   5410                 startY = location;
   5411 
   5412             a = args->next();
   5413             if (a) {
   5414                 if ((location = valueFromSideKeyword(a, isHorizontal, primitiveValueCache()))) {
   5415                     if (isHorizontal) {
   5416                         if (startX)
   5417                             return false;
   5418                         startX = location;
   5419                     } else {
   5420                         if (startY)
   5421                             return false;
   5422                         startY = location;
   5423                     }
   5424 
   5425                     a = args->next();
   5426                 }
   5427             }
   5428 
   5429             expectComma = true;
   5430         }
   5431 
   5432         if (!startX && !startY)
   5433             startY = primitiveValueCache()->createIdentifierValue(CSSValueTop);
   5434 
   5435         result->setFirstX(startX.release());
   5436         result->setFirstY(startY.release());
   5437     }
   5438 
   5439     if (!parseGradientColorStops(args, result.get(), expectComma))
   5440         return false;
   5441 
   5442     Vector<CSSGradientColorStop>& stops = result->stops();
   5443     if (stops.isEmpty())
   5444         return false;
   5445 
   5446     gradient = result.release();
   5447     return true;
   5448 }
   5449 
   5450 bool CSSParser::parseRadialGradient(RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
   5451 {
   5452     RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating);
   5453 
   5454     // Walk the arguments.
   5455     CSSParserValueList* args = m_valueList->current()->function->args.get();
   5456     if (!args || !args->size())
   5457         return false;
   5458 
   5459     CSSParserValue* a = args->current();
   5460     if (!a)
   5461         return false;
   5462 
   5463     bool expectComma = false;
   5464 
   5465     // Optional background-position
   5466     RefPtr<CSSValue> centerX;
   5467     RefPtr<CSSValue> centerY;
   5468     // parseFillPosition advances the args next pointer.
   5469     parseFillPosition(args, centerX, centerY);
   5470     a = args->current();
   5471 
   5472     if (centerX || centerY) {
   5473         // Comma
   5474         if (a->unit != CSSParserValue::Operator || a->iValue != ',')
   5475             return false;
   5476 
   5477         a = args->next();
   5478         if (!a)
   5479             return false;
   5480     }
   5481 
   5482     ASSERT(!centerX || centerX->isPrimitiveValue());
   5483     ASSERT(!centerY || centerY->isPrimitiveValue());
   5484 
   5485     result->setFirstX(static_cast<CSSPrimitiveValue*>(centerX.get()));
   5486     result->setSecondX(static_cast<CSSPrimitiveValue*>(centerX.get()));
   5487     // CSS3 radial gradients always share the same start and end point.
   5488     result->setFirstY(static_cast<CSSPrimitiveValue*>(centerY.get()));
   5489     result->setSecondY(static_cast<CSSPrimitiveValue*>(centerY.get()));
   5490 
   5491     RefPtr<CSSPrimitiveValue> shapeValue;
   5492     RefPtr<CSSPrimitiveValue> sizeValue;
   5493 
   5494     // Optional shape and/or size in any order.
   5495     for (int i = 0; i < 2; ++i) {
   5496         if (a->unit != CSSPrimitiveValue::CSS_IDENT)
   5497             break;
   5498 
   5499         bool foundValue = false;
   5500         switch (a->id) {
   5501         case CSSValueCircle:
   5502         case CSSValueEllipse:
   5503             shapeValue = primitiveValueCache()->createIdentifierValue(a->id);
   5504             foundValue = true;
   5505             break;
   5506         case CSSValueClosestSide:
   5507         case CSSValueClosestCorner:
   5508         case CSSValueFarthestSide:
   5509         case CSSValueFarthestCorner:
   5510         case CSSValueContain:
   5511         case CSSValueCover:
   5512             sizeValue = primitiveValueCache()->createIdentifierValue(a->id);
   5513             foundValue = true;
   5514             break;
   5515         }
   5516 
   5517         if (foundValue) {
   5518             a = args->next();
   5519             if (!a)
   5520                 return false;
   5521 
   5522             expectComma = true;
   5523         }
   5524     }
   5525 
   5526     result->setShape(shapeValue);
   5527     result->setSizingBehavior(sizeValue);
   5528 
   5529     // Or, two lengths or percentages
   5530     RefPtr<CSSPrimitiveValue> horizontalSize;
   5531     RefPtr<CSSPrimitiveValue> verticalSize;
   5532 
   5533     if (!shapeValue && !sizeValue) {
   5534         if (validUnit(a, FLength | FPercent, m_strict)) {
   5535             horizontalSize = primitiveValueCache()->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
   5536             a = args->next();
   5537             if (!a)
   5538                 return false;
   5539 
   5540             expectComma = true;
   5541         }
   5542 
   5543         if (validUnit(a, FLength | FPercent, m_strict)) {
   5544             verticalSize = primitiveValueCache()->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
   5545 
   5546             a = args->next();
   5547             if (!a)
   5548                 return false;
   5549             expectComma = true;
   5550         }
   5551     }
   5552 
   5553     // Must have neither or both.
   5554     if (!horizontalSize != !verticalSize)
   5555         return false;
   5556 
   5557     result->setEndHorizontalSize(horizontalSize);
   5558     result->setEndVerticalSize(verticalSize);
   5559 
   5560     if (!parseGradientColorStops(args, result.get(), expectComma))
   5561         return false;
   5562 
   5563     gradient = result.release();
   5564     return true;
   5565 }
   5566 
   5567 bool CSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
   5568 {
   5569     CSSParserValue* a = valueList->current();
   5570 
   5571     // Now look for color stops.
   5572     while (a) {
   5573         // Look for the comma before the next stop.
   5574         if (expectComma) {
   5575             if (a->unit != CSSParserValue::Operator || a->iValue != ',')
   5576                 return false;
   5577 
   5578             a = valueList->next();
   5579             if (!a)
   5580                 return false;
   5581         }
   5582 
   5583         // <color-stop> = <color> [ <percentage> | <length> ]?
   5584         CSSGradientColorStop stop;
   5585         stop.m_color = parseGradientColorOrKeyword(this, a);
   5586         if (!stop.m_color)
   5587             return false;
   5588 
   5589         a = valueList->next();
   5590         if (a) {
   5591             if (validUnit(a, FLength | FPercent, m_strict)) {
   5592                 stop.m_position = primitiveValueCache()->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit);
   5593                 a = valueList->next();
   5594             }
   5595         }
   5596 
   5597         gradient->addStop(stop);
   5598         expectComma = true;
   5599     }
   5600 
   5601     // Must have 2 or more stops to be valid.
   5602     return gradient->stops().size() > 1;
   5603 }
   5604 
   5605 bool CSSParser::isGeneratedImageValue(CSSParserValue* val) const
   5606 {
   5607     if (val->unit != CSSParserValue::Function)
   5608         return false;
   5609 
   5610     return equalIgnoringCase(val->function->name, "-webkit-gradient(")
   5611         || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
   5612         || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
   5613         || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
   5614         || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
   5615         || equalIgnoringCase(val->function->name, "-webkit-canvas(");
   5616 }
   5617 
   5618 bool CSSParser::parseGeneratedImage(RefPtr<CSSValue>& value)
   5619 {
   5620     CSSParserValue* val = m_valueList->current();
   5621 
   5622     if (val->unit != CSSParserValue::Function)
   5623         return false;
   5624 
   5625     if (equalIgnoringCase(val->function->name, "-webkit-gradient("))
   5626         return parseDeprecatedGradient(value);
   5627 
   5628     if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient("))
   5629         return parseLinearGradient(value, NonRepeating);
   5630 
   5631     if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient("))
   5632         return parseLinearGradient(value, Repeating);
   5633 
   5634     if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient("))
   5635         return parseRadialGradient(value, NonRepeating);
   5636 
   5637     if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient("))
   5638         return parseRadialGradient(value, Repeating);
   5639 
   5640     if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
   5641         return parseCanvas(value);
   5642 
   5643     return false;
   5644 }
   5645 
   5646 bool CSSParser::parseCanvas(RefPtr<CSSValue>& canvas)
   5647 {
   5648     RefPtr<CSSCanvasValue> result = CSSCanvasValue::create();
   5649 
   5650     // Walk the arguments.
   5651     CSSParserValueList* args = m_valueList->current()->function->args.get();
   5652     if (!args || args->size() != 1)
   5653         return false;
   5654 
   5655     // The first argument is the canvas name.  It is an identifier.
   5656     CSSParserValue* a = args->current();
   5657     if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
   5658         return false;
   5659     result->setName(a->string);
   5660     canvas = result;
   5661     return true;
   5662 }
   5663 
   5664 class TransformOperationInfo {
   5665 public:
   5666     TransformOperationInfo(const CSSParserString& name)
   5667     : m_type(WebKitCSSTransformValue::UnknownTransformOperation)
   5668     , m_argCount(1)
   5669     , m_allowSingleArgument(false)
   5670     , m_unit(CSSParser::FUnknown)
   5671     {
   5672         if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "scalex(") || equalIgnoringCase(name, "scaley(") || equalIgnoringCase(name, "scalez(")) {
   5673             m_unit = CSSParser::FNumber;
   5674             if (equalIgnoringCase(name, "scale("))
   5675                 m_type = WebKitCSSTransformValue::ScaleTransformOperation;
   5676             else if (equalIgnoringCase(name, "scalex("))
   5677                 m_type = WebKitCSSTransformValue::ScaleXTransformOperation;
   5678             else if (equalIgnoringCase(name, "scaley("))
   5679                 m_type = WebKitCSSTransformValue::ScaleYTransformOperation;
   5680             else
   5681                 m_type = WebKitCSSTransformValue::ScaleZTransformOperation;
   5682         } else if (equalIgnoringCase(name, "scale3d(")) {
   5683             m_type = WebKitCSSTransformValue::Scale3DTransformOperation;
   5684             m_argCount = 5;
   5685             m_unit = CSSParser::FNumber;
   5686         } else if (equalIgnoringCase(name, "rotate(")) {
   5687             m_type = WebKitCSSTransformValue::RotateTransformOperation;
   5688             m_unit = CSSParser::FAngle;
   5689         } else if (equalIgnoringCase(name, "rotatex(") ||
   5690                    equalIgnoringCase(name, "rotatey(") ||
   5691                    equalIgnoringCase(name, "rotatez(")) {
   5692             m_unit = CSSParser::FAngle;
   5693             if (equalIgnoringCase(name, "rotatex("))
   5694                 m_type = WebKitCSSTransformValue::RotateXTransformOperation;
   5695             else if (equalIgnoringCase(name, "rotatey("))
   5696                 m_type = WebKitCSSTransformValue::RotateYTransformOperation;
   5697             else
   5698                 m_type = WebKitCSSTransformValue::RotateZTransformOperation;
   5699         } else if (equalIgnoringCase(name, "rotate3d(")) {
   5700             m_type = WebKitCSSTransformValue::Rotate3DTransformOperation;
   5701             m_argCount = 7;
   5702             m_unit = CSSParser::FNumber;
   5703         } else if (equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "skewx(") || equalIgnoringCase(name, "skewy(")) {
   5704             m_unit = CSSParser::FAngle;
   5705             if (equalIgnoringCase(name, "skew("))
   5706                 m_type = WebKitCSSTransformValue::SkewTransformOperation;
   5707             else if (equalIgnoringCase(name, "skewx("))
   5708                 m_type = WebKitCSSTransformValue::SkewXTransformOperation;
   5709             else
   5710                 m_type = WebKitCSSTransformValue::SkewYTransformOperation;
   5711         } else if (equalIgnoringCase(name, "translate(") || equalIgnoringCase(name, "translatex(") || equalIgnoringCase(name, "translatey(") || equalIgnoringCase(name, "translatez(")) {
   5712             m_unit = CSSParser::FLength | CSSParser::FPercent;
   5713             if (equalIgnoringCase(name, "translate("))
   5714                 m_type = WebKitCSSTransformValue::TranslateTransformOperation;
   5715             else if (equalIgnoringCase(name, "translatex("))
   5716                 m_type = WebKitCSSTransformValue::TranslateXTransformOperation;
   5717             else if (equalIgnoringCase(name, "translatey("))
   5718                 m_type = WebKitCSSTransformValue::TranslateYTransformOperation;
   5719             else
   5720                 m_type = WebKitCSSTransformValue::TranslateZTransformOperation;
   5721         } else if (equalIgnoringCase(name, "translate3d(")) {
   5722             m_type = WebKitCSSTransformValue::Translate3DTransformOperation;
   5723             m_argCount = 5;
   5724             m_unit = CSSParser::FLength | CSSParser::FPercent;
   5725         } else if (equalIgnoringCase(name, "matrix(")) {
   5726             m_type = WebKitCSSTransformValue::MatrixTransformOperation;
   5727             m_argCount = 11;
   5728             m_unit = CSSParser::FNumber;
   5729         } else if (equalIgnoringCase(name, "matrix3d(")) {
   5730             m_type = WebKitCSSTransformValue::Matrix3DTransformOperation;
   5731             m_argCount = 31;
   5732             m_unit = CSSParser::FNumber;
   5733         } else if (equalIgnoringCase(name, "perspective(")) {
   5734             m_type = WebKitCSSTransformValue::PerspectiveTransformOperation;
   5735             m_unit = CSSParser::FNumber;
   5736         }
   5737 
   5738         if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "translate(")) {
   5739             m_allowSingleArgument = true;
   5740             m_argCount = 3;
   5741         }
   5742     }
   5743 
   5744     WebKitCSSTransformValue::TransformOperationType type() const { return m_type; }
   5745     unsigned argCount() const { return m_argCount; }
   5746     CSSParser::Units unit() const { return m_unit; }
   5747 
   5748     bool unknown() const { return m_type == WebKitCSSTransformValue::UnknownTransformOperation; }
   5749     bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
   5750 
   5751 private:
   5752     WebKitCSSTransformValue::TransformOperationType m_type;
   5753     unsigned m_argCount;
   5754     bool m_allowSingleArgument;
   5755     CSSParser::Units m_unit;
   5756 };
   5757 
   5758 PassRefPtr<CSSValueList> CSSParser::parseTransform()
   5759 {
   5760     if (!m_valueList)
   5761         return 0;
   5762 
   5763     // The transform is a list of functional primitives that specify transform operations.
   5764     // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation.
   5765     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   5766     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   5767         if (value->unit != CSSParserValue::Function || !value->function)
   5768             return 0;
   5769 
   5770         // Every primitive requires at least one argument.
   5771         CSSParserValueList* args = value->function->args.get();
   5772         if (!args)
   5773             return 0;
   5774 
   5775         // See if the specified primitive is one we understand.
   5776         TransformOperationInfo info(value->function->name);
   5777         if (info.unknown())
   5778             return 0;
   5779 
   5780         if (!info.hasCorrectArgCount(args->size()))
   5781             return 0;
   5782 
   5783         // Create the new WebKitCSSTransformValue for this operation and add it to our list.
   5784         RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(info.type());
   5785         list->append(transformValue);
   5786 
   5787         // Snag our values.
   5788         CSSParserValue* a = args->current();
   5789         unsigned argNumber = 0;
   5790         while (a) {
   5791             CSSParser::Units unit = info.unit();
   5792 
   5793             if (info.type() == WebKitCSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
   5794                 // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
   5795                 if (!validUnit(a, FAngle, true))
   5796                     return 0;
   5797             } else if (info.type() == WebKitCSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
   5798                 // 3rd param of translate3d() cannot be a percentage
   5799                 if (!validUnit(a, FLength, true))
   5800                     return 0;
   5801             } else if (info.type() == WebKitCSSTransformValue::TranslateZTransformOperation && argNumber == 0) {
   5802                 // 1st param of translateZ() cannot be a percentage
   5803                 if (!validUnit(a, FLength, true))
   5804                     return 0;
   5805             } else if (info.type() == WebKitCSSTransformValue::PerspectiveTransformOperation && argNumber == 0) {
   5806                 // 1st param of perspective() must be a non-negative number (deprecated) or length.
   5807                 if (!validUnit(a, FNumber | FLength | FNonNeg, true))
   5808                     return 0;
   5809             } else if (!validUnit(a, unit, true))
   5810                 return 0;
   5811 
   5812             // Add the value to the current transform operation.
   5813             transformValue->append(primitiveValueCache()->createValue(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit));
   5814 
   5815             a = args->next();
   5816             if (!a)
   5817                 break;
   5818             if (a->unit != CSSParserValue::Operator || a->iValue != ',')
   5819                 return 0;
   5820             a = args->next();
   5821 
   5822             argNumber++;
   5823         }
   5824     }
   5825 
   5826     return list.release();
   5827 }
   5828 
   5829 bool CSSParser::parseTransformOrigin(int propId, int& propId1, int& propId2, int& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
   5830 {
   5831     propId1 = propId;
   5832     propId2 = propId;
   5833     propId3 = propId;
   5834     if (propId == CSSPropertyWebkitTransformOrigin) {
   5835         propId1 = CSSPropertyWebkitTransformOriginX;
   5836         propId2 = CSSPropertyWebkitTransformOriginY;
   5837         propId3 = CSSPropertyWebkitTransformOriginZ;
   5838     }
   5839 
   5840     switch (propId) {
   5841         case CSSPropertyWebkitTransformOrigin:
   5842             if (!parseTransformOriginShorthand(value, value2, value3))
   5843                 return false;
   5844             // parseTransformOriginShorthand advances the m_valueList pointer
   5845             break;
   5846         case CSSPropertyWebkitTransformOriginX: {
   5847             value = parseFillPositionX(m_valueList);
   5848             if (value)
   5849                 m_valueList->next();
   5850             break;
   5851         }
   5852         case CSSPropertyWebkitTransformOriginY: {
   5853             value = parseFillPositionY(m_valueList);
   5854             if (value)
   5855                 m_valueList->next();
   5856             break;
   5857         }
   5858         case CSSPropertyWebkitTransformOriginZ: {
   5859             if (validUnit(m_valueList->current(), FLength, m_strict))
   5860                 value = primitiveValueCache()->createValue(m_valueList->current()->fValue, (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit);
   5861             if (value)
   5862                 m_valueList->next();
   5863             break;
   5864         }
   5865     }
   5866 
   5867     return value;
   5868 }
   5869 
   5870 bool CSSParser::parsePerspectiveOrigin(int propId, int& propId1, int& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2)
   5871 {
   5872     propId1 = propId;
   5873     propId2 = propId;
   5874     if (propId == CSSPropertyWebkitPerspectiveOrigin) {
   5875         propId1 = CSSPropertyWebkitPerspectiveOriginX;
   5876         propId2 = CSSPropertyWebkitPerspectiveOriginY;
   5877     }
   5878 
   5879     switch (propId) {
   5880         case CSSPropertyWebkitPerspectiveOrigin:
   5881             parseFillPosition(m_valueList, value, value2);
   5882             break;
   5883         case CSSPropertyWebkitPerspectiveOriginX: {
   5884             value = parseFillPositionX(m_valueList);
   5885             if (value)
   5886                 m_valueList->next();
   5887             break;
   5888         }
   5889         case CSSPropertyWebkitPerspectiveOriginY: {
   5890             value = parseFillPositionY(m_valueList);
   5891             if (value)
   5892                 m_valueList->next();
   5893             break;
   5894         }
   5895     }
   5896 
   5897     return value;
   5898 }
   5899 
   5900 bool CSSParser::parseTextEmphasisStyle(bool important)
   5901 {
   5902     unsigned valueListSize = m_valueList->size();
   5903 
   5904     RefPtr<CSSPrimitiveValue> fill;
   5905     RefPtr<CSSPrimitiveValue> shape;
   5906 
   5907     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   5908         if (value->unit == CSSPrimitiveValue::CSS_STRING) {
   5909             if (fill || shape || (valueListSize != 1 && !inShorthand()))
   5910                 return false;
   5911             addProperty(CSSPropertyWebkitTextEmphasisStyle, primitiveValueCache()->createValue(value->string, CSSPrimitiveValue::CSS_STRING), important);
   5912             m_valueList->next();
   5913             return true;
   5914         }
   5915 
   5916         if (value->id == CSSValueNone) {
   5917             if (fill || shape || (valueListSize != 1 && !inShorthand()))
   5918                 return false;
   5919             addProperty(CSSPropertyWebkitTextEmphasisStyle, primitiveValueCache()->createIdentifierValue(CSSValueNone), important);
   5920             m_valueList->next();
   5921             return true;
   5922         }
   5923 
   5924         if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
   5925             if (fill)
   5926                 return false;
   5927             fill = primitiveValueCache()->createIdentifierValue(value->id);
   5928         } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
   5929             if (shape)
   5930                 return false;
   5931             shape = primitiveValueCache()->createIdentifierValue(value->id);
   5932         } else if (!inShorthand())
   5933             return false;
   5934         else
   5935             break;
   5936     }
   5937 
   5938     if (fill && shape) {
   5939         RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
   5940         parsedValues->append(fill.release());
   5941         parsedValues->append(shape.release());
   5942         addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
   5943         return true;
   5944     }
   5945     if (fill) {
   5946         addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
   5947         return true;
   5948     }
   5949     if (shape) {
   5950         addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
   5951         return true;
   5952     }
   5953 
   5954     return false;
   5955 }
   5956 
   5957 bool CSSParser::parseLineBoxContain(bool important)
   5958 {
   5959     LineBoxContain lineBoxContain = LineBoxContainNone;
   5960 
   5961     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   5962         if (value->id == CSSValueBlock) {
   5963             if (lineBoxContain & LineBoxContainBlock)
   5964                 return false;
   5965             lineBoxContain |= LineBoxContainBlock;
   5966         } else if (value->id == CSSValueInline) {
   5967             if (lineBoxContain & LineBoxContainInline)
   5968                 return false;
   5969             lineBoxContain |= LineBoxContainInline;
   5970         } else if (value->id == CSSValueFont) {
   5971             if (lineBoxContain & LineBoxContainFont)
   5972                 return false;
   5973             lineBoxContain |= LineBoxContainFont;
   5974         } else if (value->id == CSSValueGlyphs) {
   5975             if (lineBoxContain & LineBoxContainGlyphs)
   5976                 return false;
   5977             lineBoxContain |= LineBoxContainGlyphs;
   5978         } else if (value->id == CSSValueReplaced) {
   5979             if (lineBoxContain & LineBoxContainReplaced)
   5980                 return false;
   5981             lineBoxContain |= LineBoxContainReplaced;
   5982         } else if (value->id == CSSValueInlineBox) {
   5983             if (lineBoxContain & LineBoxContainInlineBox)
   5984                 return false;
   5985             lineBoxContain |= LineBoxContainInlineBox;
   5986         } else
   5987             return false;
   5988     }
   5989 
   5990     if (!lineBoxContain)
   5991         return false;
   5992 
   5993     addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
   5994     return true;
   5995 }
   5996 
   5997 static inline int yyerror(const char*) { return 1; }
   5998 
   5999 #define END_TOKEN 0
   6000 
   6001 #include "CSSGrammar.h"
   6002 
   6003 int CSSParser::lex(void* yylvalWithoutType)
   6004 {
   6005     YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType);
   6006     int length;
   6007 
   6008     lex();
   6009 
   6010     UChar* t = text(&length);
   6011 
   6012     switch (token()) {
   6013     case WHITESPACE:
   6014     case SGML_CD:
   6015     case INCLUDES:
   6016     case DASHMATCH:
   6017         break;
   6018 
   6019     case URI:
   6020     case STRING:
   6021     case IDENT:
   6022     case NTH:
   6023     case HEX:
   6024     case IDSEL:
   6025     case DIMEN:
   6026     case UNICODERANGE:
   6027     case FUNCTION:
   6028     case ANYFUNCTION:
   6029     case NOTFUNCTION:
   6030     case CALCFUNCTION:
   6031     case MINFUNCTION:
   6032     case MAXFUNCTION:
   6033         yylval->string.characters = t;
   6034         yylval->string.length = length;
   6035         break;
   6036 
   6037     case IMPORT_SYM:
   6038     case PAGE_SYM:
   6039     case MEDIA_SYM:
   6040     case FONT_FACE_SYM:
   6041     case CHARSET_SYM:
   6042     case NAMESPACE_SYM:
   6043     case WEBKIT_KEYFRAMES_SYM:
   6044 
   6045     case IMPORTANT_SYM:
   6046         break;
   6047 
   6048     case QEMS:
   6049         length--;
   6050     case GRADS:
   6051     case TURNS:
   6052         length--;
   6053     case DEGS:
   6054     case RADS:
   6055     case KHERTZ:
   6056     case REMS:
   6057         length--;
   6058     case MSECS:
   6059     case HERTZ:
   6060     case EMS:
   6061     case EXS:
   6062     case PXS:
   6063     case CMS:
   6064     case MMS:
   6065     case INS:
   6066     case PTS:
   6067     case PCS:
   6068         length--;
   6069     case SECS:
   6070     case PERCENTAGE:
   6071         length--;
   6072     case FLOATTOKEN:
   6073     case INTEGER:
   6074         yylval->number = charactersToDouble(t, length);
   6075         break;
   6076 
   6077     default:
   6078         break;
   6079     }
   6080 
   6081     return token();
   6082 }
   6083 
   6084 void CSSParser::recheckAtKeyword(const UChar* str, int len)
   6085 {
   6086     String ruleName(str, len);
   6087     if (equalIgnoringCase(ruleName, "@import"))
   6088         yyTok = IMPORT_SYM;
   6089     else if (equalIgnoringCase(ruleName, "@page"))
   6090         yyTok = PAGE_SYM;
   6091     else if (equalIgnoringCase(ruleName, "@media"))
   6092         yyTok = MEDIA_SYM;
   6093     else if (equalIgnoringCase(ruleName, "@font-face"))
   6094         yyTok = FONT_FACE_SYM;
   6095     else if (equalIgnoringCase(ruleName, "@charset"))
   6096         yyTok = CHARSET_SYM;
   6097     else if (equalIgnoringCase(ruleName, "@namespace"))
   6098         yyTok = NAMESPACE_SYM;
   6099     else if (equalIgnoringCase(ruleName, "@-webkit-keyframes"))
   6100         yyTok = WEBKIT_KEYFRAMES_SYM;
   6101     else if (equalIgnoringCase(ruleName, "@-webkit-mediaquery"))
   6102         yyTok = WEBKIT_MEDIAQUERY_SYM;
   6103 }
   6104 
   6105 UChar* CSSParser::text(int *length)
   6106 {
   6107     UChar* start = yytext;
   6108     int l = yyleng;
   6109     switch (yyTok) {
   6110     case STRING:
   6111         l--;
   6112         /* nobreak */
   6113     case HEX:
   6114     case IDSEL:
   6115         start++;
   6116         l--;
   6117         break;
   6118     case URI:
   6119         // "url("{w}{string}{w}")"
   6120         // "url("{w}{url}{w}")"
   6121         // strip "url(" and ")"
   6122         start += 4;
   6123         l -= 5;
   6124         // strip {w}
   6125         while (l && isHTMLSpace(*start)) {
   6126             ++start;
   6127             --l;
   6128         }
   6129         while (l && isHTMLSpace(start[l - 1]))
   6130             --l;
   6131         if (l && (*start == '"' || *start == '\'')) {
   6132             ASSERT(l >= 2 && start[l - 1] == *start);
   6133             ++start;
   6134             l -= 2;
   6135         }
   6136         break;
   6137     default:
   6138         break;
   6139     }
   6140 
   6141     // process escapes
   6142     UChar* out = start;
   6143     UChar* escape = 0;
   6144 
   6145     bool sawEscape = false;
   6146 
   6147     for (int i = 0; i < l; i++) {
   6148         UChar* current = start + i;
   6149         if (escape == current - 1) {
   6150             if (isASCIIHexDigit(*current))
   6151                 continue;
   6152             if (yyTok == STRING &&
   6153                  (*current == '\n' || *current == '\r' || *current == '\f')) {
   6154                 // ### handle \r\n case
   6155                 if (*current != '\r')
   6156                     escape = 0;
   6157                 continue;
   6158             }
   6159             // in all other cases copy the char to output
   6160             // ###
   6161             *out++ = *current;
   6162             escape = 0;
   6163             continue;
   6164         }
   6165         if (escape == current - 2 && yyTok == STRING &&
   6166              *(current-1) == '\r' && *current == '\n') {
   6167             escape = 0;
   6168             continue;
   6169         }
   6170         if (escape > current - 7 && isASCIIHexDigit(*current))
   6171             continue;
   6172         if (escape) {
   6173             // add escaped char
   6174             unsigned uc = 0;
   6175             escape++;
   6176             while (escape < current) {
   6177                 uc *= 16;
   6178                 uc += toASCIIHexValue(*escape);
   6179                 escape++;
   6180             }
   6181             // can't handle chars outside ucs2
   6182             if (uc > 0xffff)
   6183                 uc = 0xfffd;
   6184             *out++ = uc;
   6185             escape = 0;
   6186             if (isHTMLSpace(*current))
   6187                 continue;
   6188         }
   6189         if (!escape && *current == '\\') {
   6190             escape = current;
   6191             sawEscape = true;
   6192             continue;
   6193         }
   6194         *out++ = *current;
   6195     }
   6196     if (escape) {
   6197         // add escaped char
   6198         unsigned uc = 0;
   6199         escape++;
   6200         while (escape < start+l) {
   6201             uc *= 16;
   6202             uc += toASCIIHexValue(*escape);
   6203             escape++;
   6204         }
   6205         // can't handle chars outside ucs2
   6206         if (uc > 0xffff)
   6207             uc = 0xfffd;
   6208         *out++ = uc;
   6209     }
   6210 
   6211     *length = out - start;
   6212 
   6213     // If we have an unrecognized @-keyword, and if we handled any escapes at all, then
   6214     // we should attempt to adjust yyTok to the correct type.
   6215     if (yyTok == ATKEYWORD && sawEscape)
   6216         recheckAtKeyword(start, *length);
   6217 
   6218     return start;
   6219 }
   6220 
   6221 void CSSParser::countLines()
   6222 {
   6223     for (UChar* current = yytext; current < yytext + yyleng; ++current) {
   6224         if (*current == '\n')
   6225             ++m_lineNumber;
   6226     }
   6227 }
   6228 
   6229 CSSParserSelector* CSSParser::createFloatingSelector()
   6230 {
   6231     CSSParserSelector* selector = new CSSParserSelector;
   6232     m_floatingSelectors.add(selector);
   6233     return selector;
   6234 }
   6235 
   6236 PassOwnPtr<CSSParserSelector> CSSParser::sinkFloatingSelector(CSSParserSelector* selector)
   6237 {
   6238     if (selector) {
   6239         ASSERT(m_floatingSelectors.contains(selector));
   6240         m_floatingSelectors.remove(selector);
   6241     }
   6242     return adoptPtr(selector);
   6243 }
   6244 
   6245 Vector<OwnPtr<CSSParserSelector> >* CSSParser::createFloatingSelectorVector()
   6246 {
   6247     Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >;
   6248     m_floatingSelectorVectors.add(selectorVector);
   6249     return selectorVector;
   6250 }
   6251 
   6252 PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > CSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector)
   6253 {
   6254     if (selectorVector) {
   6255         ASSERT(m_floatingSelectorVectors.contains(selectorVector));
   6256         m_floatingSelectorVectors.remove(selectorVector);
   6257     }
   6258     return adoptPtr(selectorVector);
   6259 }
   6260 
   6261 CSSParserValueList* CSSParser::createFloatingValueList()
   6262 {
   6263     CSSParserValueList* list = new CSSParserValueList;
   6264     m_floatingValueLists.add(list);
   6265     return list;
   6266 }
   6267 
   6268 CSSParserValueList* CSSParser::sinkFloatingValueList(CSSParserValueList* list)
   6269 {
   6270     if (list) {
   6271         ASSERT(m_floatingValueLists.contains(list));
   6272         m_floatingValueLists.remove(list);
   6273     }
   6274     return list;
   6275 }
   6276 
   6277 CSSParserFunction* CSSParser::createFloatingFunction()
   6278 {
   6279     CSSParserFunction* function = new CSSParserFunction;
   6280     m_floatingFunctions.add(function);
   6281     return function;
   6282 }
   6283 
   6284 CSSParserFunction* CSSParser::sinkFloatingFunction(CSSParserFunction* function)
   6285 {
   6286     if (function) {
   6287         ASSERT(m_floatingFunctions.contains(function));
   6288         m_floatingFunctions.remove(function);
   6289     }
   6290     return function;
   6291 }
   6292 
   6293 CSSParserValue& CSSParser::sinkFloatingValue(CSSParserValue& value)
   6294 {
   6295     if (value.unit == CSSParserValue::Function) {
   6296         ASSERT(m_floatingFunctions.contains(value.function));
   6297         m_floatingFunctions.remove(value.function);
   6298     }
   6299     return value;
   6300 }
   6301 
   6302 MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
   6303 {
   6304     m_floatingMediaQueryExp = MediaQueryExp::create(mediaFeature, values);
   6305     return m_floatingMediaQueryExp.get();
   6306 }
   6307 
   6308 PassOwnPtr<MediaQueryExp> CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression)
   6309 {
   6310     ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp);
   6311     return m_floatingMediaQueryExp.release();
   6312 }
   6313 
   6314 Vector<OwnPtr<MediaQueryExp> >* CSSParser::createFloatingMediaQueryExpList()
   6315 {
   6316     m_floatingMediaQueryExpList = adoptPtr(new Vector<OwnPtr<MediaQueryExp> >);
   6317     return m_floatingMediaQueryExpList.get();
   6318 }
   6319 
   6320 PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > CSSParser::sinkFloatingMediaQueryExpList(Vector<OwnPtr<MediaQueryExp> >* list)
   6321 {
   6322     ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList);
   6323     return m_floatingMediaQueryExpList.release();
   6324 }
   6325 
   6326 MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const String& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
   6327 {
   6328     m_floatingMediaQuery = adoptPtr(new MediaQuery(restrictor, mediaType, expressions));
   6329     return m_floatingMediaQuery.get();
   6330 }
   6331 
   6332 MediaQuery* CSSParser::createFloatingMediaQuery(PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
   6333 {
   6334     return createFloatingMediaQuery(MediaQuery::None, "all", expressions);
   6335 }
   6336 
   6337 PassOwnPtr<MediaQuery> CSSParser::sinkFloatingMediaQuery(MediaQuery* query)
   6338 {
   6339     ASSERT_UNUSED(query, query == m_floatingMediaQuery);
   6340     return m_floatingMediaQuery.release();
   6341 }
   6342 
   6343 MediaList* CSSParser::createMediaList()
   6344 {
   6345     RefPtr<MediaList> list = MediaList::create();
   6346     MediaList* result = list.get();
   6347     m_parsedStyleObjects.append(list.release());
   6348     return result;
   6349 }
   6350 
   6351 CSSRule* CSSParser::createCharsetRule(const CSSParserString& charset)
   6352 {
   6353     if (!m_styleSheet)
   6354         return 0;
   6355     RefPtr<CSSCharsetRule> rule = CSSCharsetRule::create(m_styleSheet, charset);
   6356     CSSCharsetRule* result = rule.get();
   6357     m_parsedStyleObjects.append(rule.release());
   6358     return result;
   6359 }
   6360 
   6361 CSSRule* CSSParser::createImportRule(const CSSParserString& url, MediaList* media)
   6362 {
   6363     if (!media || !m_styleSheet || !m_allowImportRules)
   6364         return 0;
   6365     RefPtr<CSSImportRule> rule = CSSImportRule::create(m_styleSheet, url, media);
   6366     CSSImportRule* result = rule.get();
   6367     m_parsedStyleObjects.append(rule.release());
   6368     return result;
   6369 }
   6370 
   6371 CSSRule* CSSParser::createMediaRule(MediaList* media, CSSRuleList* rules)
   6372 {
   6373     if (!media || !rules || !m_styleSheet)
   6374         return 0;
   6375     m_allowImportRules = m_allowNamespaceDeclarations = false;
   6376     RefPtr<CSSMediaRule> rule = CSSMediaRule::create(m_styleSheet, media, rules);
   6377     CSSMediaRule* result = rule.get();
   6378     m_parsedStyleObjects.append(rule.release());
   6379     return result;
   6380 }
   6381 
   6382 CSSRuleList* CSSParser::createRuleList()
   6383 {
   6384     RefPtr<CSSRuleList> list = CSSRuleList::create();
   6385     CSSRuleList* listPtr = list.get();
   6386 
   6387     m_parsedRuleLists.append(list.release());
   6388     return listPtr;
   6389 }
   6390 
   6391 WebKitCSSKeyframesRule* CSSParser::createKeyframesRule()
   6392 {
   6393     m_allowImportRules = m_allowNamespaceDeclarations = false;
   6394     RefPtr<WebKitCSSKeyframesRule> rule = WebKitCSSKeyframesRule::create(m_styleSheet);
   6395     WebKitCSSKeyframesRule* rulePtr = rule.get();
   6396     m_parsedStyleObjects.append(rule.release());
   6397     return rulePtr;
   6398 }
   6399 
   6400 CSSRule* CSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors)
   6401 {
   6402     CSSStyleRule* result = 0;
   6403     markRuleBodyEnd();
   6404     if (selectors) {
   6405         m_allowImportRules = m_allowNamespaceDeclarations = false;
   6406         RefPtr<CSSStyleRule> rule = CSSStyleRule::create(m_styleSheet, m_lastSelectorLineNumber);
   6407         rule->adoptSelectorVector(*selectors);
   6408         if (m_hasFontFaceOnlyValues)
   6409             deleteFontFaceOnlyValues();
   6410         rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties));
   6411         result = rule.get();
   6412         m_parsedStyleObjects.append(rule.release());
   6413         if (m_ruleRangeMap) {
   6414             ASSERT(m_currentRuleData);
   6415             m_currentRuleData->styleSourceData->styleBodyRange = m_ruleBodyRange;
   6416             m_currentRuleData->selectorListRange = m_selectorListRange;
   6417             m_ruleRangeMap->set(result, m_currentRuleData.release());
   6418             m_currentRuleData = CSSRuleSourceData::create();
   6419             m_currentRuleData->styleSourceData = CSSStyleSourceData::create();
   6420             m_inStyleRuleOrDeclaration = false;
   6421         }
   6422     }
   6423     resetSelectorListMarks();
   6424     resetRuleBodyMarks();
   6425     clearProperties();
   6426     return result;
   6427 }
   6428 
   6429 CSSRule* CSSParser::createFontFaceRule()
   6430 {
   6431     m_allowImportRules = m_allowNamespaceDeclarations = false;
   6432     for (unsigned i = 0; i < m_numParsedProperties; ++i) {
   6433         CSSProperty* property = m_parsedProperties[i];
   6434         int id = property->id();
   6435         if ((id == CSSPropertyFontWeight || id == CSSPropertyFontStyle || id == CSSPropertyFontVariant) && property->value()->isPrimitiveValue()) {
   6436             RefPtr<CSSValue> value = property->m_value.release();
   6437             property->m_value = CSSValueList::createCommaSeparated();
   6438             static_cast<CSSValueList*>(property->value())->append(value.release());
   6439         } else if (id == CSSPropertyFontFamily && (!property->value()->isValueList() || static_cast<CSSValueList*>(property->value())->length() != 1)) {
   6440             // Unlike font-family property, font-family descriptor in @font-face rule
   6441             // has to be a value list with exactly one family name. It cannot have a
   6442             // have 'initial' value and cannot 'inherit' from parent.
   6443             // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
   6444             clearProperties();
   6445             return 0;
   6446         }
   6447     }
   6448     RefPtr<CSSFontFaceRule> rule = CSSFontFaceRule::create(m_styleSheet);
   6449     rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties));
   6450     clearProperties();
   6451     CSSFontFaceRule* result = rule.get();
   6452     m_parsedStyleObjects.append(rule.release());
   6453     return result;
   6454 }
   6455 
   6456 void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
   6457 {
   6458     if (!m_styleSheet || !m_allowNamespaceDeclarations)
   6459         return;
   6460     m_allowImportRules = false;
   6461     m_styleSheet->addNamespace(this, prefix, uri);
   6462 }
   6463 
   6464 void CSSParser::updateSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers)
   6465 {
   6466     AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
   6467     QualifiedName tag = QualifiedName(namespacePrefix, elementName, determinedNamespace);
   6468     if (!specifiers->isUnknownPseudoElement()) {
   6469         specifiers->setTag(tag);
   6470         return;
   6471     }
   6472 
   6473     specifiers->setRelation(CSSSelector::ShadowDescendant);
   6474     if (CSSParserSelector* history = specifiers->tagHistory()) {
   6475         history->setTag(tag);
   6476         return;
   6477     }
   6478 
   6479     // No need to create an extra element name selector if we are matching any element
   6480     // in any namespace.
   6481     if (elementName == starAtom && m_defaultNamespace == starAtom)
   6482         return;
   6483 
   6484     CSSParserSelector* elementNameSelector = new CSSParserSelector;
   6485     elementNameSelector->setTag(tag);
   6486     specifiers->setTagHistory(elementNameSelector);
   6487 }
   6488 
   6489 
   6490 CSSRule* CSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector)
   6491 {
   6492     // FIXME: Margin at-rules are ignored.
   6493     m_allowImportRules = m_allowNamespaceDeclarations = false;
   6494     CSSPageRule* pageRule = 0;
   6495     if (pageSelector) {
   6496         RefPtr<CSSPageRule> rule = CSSPageRule::create(m_styleSheet, m_lastSelectorLineNumber);
   6497         Vector<OwnPtr<CSSParserSelector> > selectorVector;
   6498         selectorVector.append(pageSelector);
   6499         rule->adoptSelectorVector(selectorVector);
   6500         rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties));
   6501         pageRule = rule.get();
   6502         m_parsedStyleObjects.append(rule.release());
   6503     }
   6504     clearProperties();
   6505     return pageRule;
   6506 }
   6507 
   6508 CSSRule* CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
   6509 {
   6510     // FIXME: Implement margin at-rule here, using:
   6511     //        - marginBox: margin box
   6512     //        - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_numParsedProperties) are for this at-rule.
   6513     // Don't forget to also update the action for page symbol in CSSGrammar.y such that margin at-rule data is cleared if page_selector is invalid.
   6514 
   6515     endDeclarationsForMarginBox();
   6516     return 0; // until this method is implemented.
   6517 }
   6518 
   6519 void CSSParser::startDeclarationsForMarginBox()
   6520 {
   6521     m_numParsedPropertiesBeforeMarginBox = m_numParsedProperties;
   6522 }
   6523 
   6524 void CSSParser::endDeclarationsForMarginBox()
   6525 {
   6526     ASSERT(m_numParsedPropertiesBeforeMarginBox != INVALID_NUM_PARSED_PROPERTIES);
   6527     rollbackLastProperties(m_numParsedProperties - m_numParsedPropertiesBeforeMarginBox);
   6528     m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
   6529 }
   6530 
   6531 void CSSParser::deleteFontFaceOnlyValues()
   6532 {
   6533     ASSERT(m_hasFontFaceOnlyValues);
   6534     int deletedProperties = 0;
   6535 
   6536     for (unsigned i = 0; i < m_numParsedProperties; ++i) {
   6537         CSSProperty* property = m_parsedProperties[i];
   6538         int id = property->id();
   6539         if ((id == CSSPropertyFontWeight || id == CSSPropertyFontStyle || id == CSSPropertyFontVariant) && property->value()->isValueList()) {
   6540             delete property;
   6541             deletedProperties++;
   6542         } else if (deletedProperties)
   6543             m_parsedProperties[i - deletedProperties] = m_parsedProperties[i];
   6544     }
   6545 
   6546     m_numParsedProperties -= deletedProperties;
   6547 }
   6548 
   6549 WebKitCSSKeyframeRule* CSSParser::createKeyframeRule(CSSParserValueList* keys)
   6550 {
   6551     // Create a key string from the passed keys
   6552     String keyString;
   6553     for (unsigned i = 0; i < keys->size(); ++i) {
   6554         float key = (float) keys->valueAt(i)->fValue;
   6555         if (i != 0)
   6556             keyString += ",";
   6557         keyString += String::number(key);
   6558         keyString += "%";
   6559     }
   6560 
   6561     RefPtr<WebKitCSSKeyframeRule> keyframe = WebKitCSSKeyframeRule::create(m_styleSheet);
   6562     keyframe->setKeyText(keyString);
   6563     keyframe->setDeclaration(CSSMutableStyleDeclaration::create(0, m_parsedProperties, m_numParsedProperties));
   6564 
   6565     clearProperties();
   6566 
   6567     WebKitCSSKeyframeRule* keyframePtr = keyframe.get();
   6568     m_parsedStyleObjects.append(keyframe.release());
   6569     return keyframePtr;
   6570 }
   6571 
   6572 void CSSParser::invalidBlockHit()
   6573 {
   6574     if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
   6575         m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
   6576 }
   6577 
   6578 void CSSParser::updateLastSelectorLineAndPosition()
   6579 {
   6580     m_lastSelectorLineNumber = m_lineNumber;
   6581     markRuleBodyStart();
   6582 }
   6583 
   6584 void CSSParser::markSelectorListStart()
   6585 {
   6586     m_selectorListRange.start = yytext - m_data;
   6587 }
   6588 
   6589 void CSSParser::markSelectorListEnd()
   6590 {
   6591     if (!m_currentRuleData)
   6592         return;
   6593     UChar* listEnd = yytext;
   6594     while (listEnd > m_data + 1) {
   6595         if (isHTMLSpace(*(listEnd - 1)))
   6596             --listEnd;
   6597         else
   6598             break;
   6599     }
   6600     m_selectorListRange.end = listEnd - m_data;
   6601 }
   6602 
   6603 void CSSParser::markRuleBodyStart()
   6604 {
   6605     unsigned offset = yytext - m_data;
   6606     if (*yytext == '{')
   6607         ++offset; // Skip the rule body opening brace.
   6608     if (offset > m_ruleBodyRange.start)
   6609         m_ruleBodyRange.start = offset;
   6610     m_inStyleRuleOrDeclaration = true;
   6611 }
   6612 
   6613 void CSSParser::markRuleBodyEnd()
   6614 {
   6615     unsigned offset = yytext - m_data;
   6616     if (offset > m_ruleBodyRange.end)
   6617         m_ruleBodyRange.end = offset;
   6618 }
   6619 
   6620 void CSSParser::markPropertyStart()
   6621 {
   6622     if (!m_inStyleRuleOrDeclaration)
   6623         return;
   6624     m_propertyRange.start = yytext - m_data;
   6625 }
   6626 
   6627 void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed)
   6628 {
   6629     if (!m_inStyleRuleOrDeclaration)
   6630         return;
   6631     unsigned offset = yytext - m_data;
   6632     if (*yytext == ';') // Include semicolon into the property text.
   6633         ++offset;
   6634     m_propertyRange.end = offset;
   6635     if (m_propertyRange.start != UINT_MAX && m_currentRuleData) {
   6636         // This stuff is only executed when the style data retrieval is requested by client.
   6637         const unsigned start = m_propertyRange.start;
   6638         const unsigned end = m_propertyRange.end;
   6639         ASSERT(start < end);
   6640         String propertyString = String(m_data + start, end - start).stripWhiteSpace();
   6641         if (propertyString.endsWith(";", true))
   6642             propertyString = propertyString.left(propertyString.length() - 1);
   6643         Vector<String> propertyComponents;
   6644         size_t colonIndex = propertyString.find(":");
   6645         ASSERT(colonIndex != notFound);
   6646 
   6647         String name = propertyString.left(colonIndex).stripWhiteSpace();
   6648         String value = propertyString.substring(colonIndex + 1, propertyString.length()).stripWhiteSpace();
   6649         // The property range is relative to the declaration start offset.
   6650         m_currentRuleData->styleSourceData->propertyData.append(
   6651             CSSPropertySourceData(name, value, isImportantFound, isPropertyParsed, SourceRange(start - m_ruleBodyRange.start, end - m_ruleBodyRange.start)));
   6652     }
   6653     resetPropertyMarks();
   6654 }
   6655 
   6656 static int cssPropertyID(const UChar* propertyName, unsigned length)
   6657 {
   6658     if (!length)
   6659         return 0;
   6660     if (length > maxCSSPropertyNameLength)
   6661         return 0;
   6662 
   6663     char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
   6664 
   6665     for (unsigned i = 0; i != length; ++i) {
   6666         UChar c = propertyName[i];
   6667         if (c == 0 || c >= 0x7F)
   6668             return 0; // illegal character
   6669         buffer[i] = toASCIILower(c);
   6670     }
   6671     buffer[length] = '\0';
   6672 
   6673     const char* name = buffer;
   6674     if (buffer[0] == '-') {
   6675         // If the prefix is -apple- or -khtml-, change it to -webkit-.
   6676         // This makes the string one character longer.
   6677         if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
   6678             memmove(buffer + 7, buffer + 6, length + 1 - 6);
   6679             memcpy(buffer, "-webkit", 7);
   6680             ++length;
   6681         }
   6682 
   6683         if (hasPrefix(buffer, length, "-webkit")) {
   6684             if (!strcmp(buffer, "-webkit-box-sizing")) {
   6685                 // -webkit-box-sizing worked in Safari 4 and earlier.
   6686                 const char* const boxSizing = "box-sizing";
   6687                 name = boxSizing;
   6688                 length = strlen(boxSizing);
   6689             } else if (!strcmp(buffer, "-webkit-opacity")) {
   6690                 // Honor -webkit-opacity as a synonym for opacity.
   6691                 // This was the only syntax that worked in Safari 1.1, and may be in use on some websites and widgets.
   6692                 const char* const opacity = "opacity";
   6693                 name = opacity;
   6694                 length = strlen(opacity);
   6695 #if PLATFORM(IOS)
   6696             } else if (!strcmp(buffer, "-webkit-hyphenate-locale")) {
   6697                 // Worked in iOS 4.2.
   6698                 const char* const webkitLocale = "-webkit-locale";
   6699                 name = webkitLocale;
   6700                 length = strlen(webkitLocale);
   6701 #endif
   6702             } else if (hasPrefix(buffer + 7, length - 7, "-border-")) {
   6703                 // -webkit-border-*-*-radius worked in Safari 4 and earlier. -webkit-border-radius syntax
   6704                 // differs from border-radius, so it is remains as a distinct property.
   6705                 if (!strcmp(buffer + 15, "top-left-radius")
   6706                         || !strcmp(buffer + 15, "top-right-radius")
   6707                         || !strcmp(buffer + 15, "bottom-right-radius")
   6708                         || !strcmp(buffer + 15, "bottom-left-radius")) {
   6709                     name = buffer + 8;
   6710                     length -= 8;
   6711                 }
   6712             }
   6713         }
   6714     }
   6715 
   6716     const Property* hashTableEntry = findProperty(name, length);
   6717     return hashTableEntry ? hashTableEntry->id : 0;
   6718 }
   6719 
   6720 int cssPropertyID(const String& string)
   6721 {
   6722     return cssPropertyID(string.characters(), string.length());
   6723 }
   6724 
   6725 int cssPropertyID(const CSSParserString& string)
   6726 {
   6727     return cssPropertyID(string.characters, string.length);
   6728 }
   6729 
   6730 int cssValueKeywordID(const CSSParserString& string)
   6731 {
   6732     unsigned length = string.length;
   6733     if (!length)
   6734         return 0;
   6735     if (length > maxCSSValueKeywordLength)
   6736         return 0;
   6737 
   6738     char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
   6739 
   6740     for (unsigned i = 0; i != length; ++i) {
   6741         UChar c = string.characters[i];
   6742         if (c == 0 || c >= 0x7F)
   6743             return 0; // illegal character
   6744         buffer[i] = WTF::toASCIILower(c);
   6745     }
   6746     buffer[length] = '\0';
   6747 
   6748     if (buffer[0] == '-') {
   6749         // If the prefix is -apple- or -khtml-, change it to -webkit-.
   6750         // This makes the string one character longer.
   6751         if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
   6752             memmove(buffer + 7, buffer + 6, length + 1 - 6);
   6753             memcpy(buffer, "-webkit", 7);
   6754             ++length;
   6755         }
   6756     }
   6757 
   6758     const Value* hashTableEntry = findValue(buffer, length);
   6759     return hashTableEntry ? hashTableEntry->id : 0;
   6760 }
   6761 
   6762 // "ident" from the CSS tokenizer, minus backslash-escape sequences
   6763 static bool isCSSTokenizerIdentifier(const String& string)
   6764 {
   6765     const UChar* p = string.characters();
   6766     const UChar* end = p + string.length();
   6767 
   6768     // -?
   6769     if (p != end && p[0] == '-')
   6770         ++p;
   6771 
   6772     // {nmstart}
   6773     if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p[0])))
   6774         return false;
   6775     ++p;
   6776 
   6777     // {nmchar}*
   6778     for (; p != end; ++p) {
   6779         if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p[0])))
   6780             return false;
   6781     }
   6782 
   6783     return true;
   6784 }
   6785 
   6786 // "url" from the CSS tokenizer, minus backslash-escape sequences
   6787 static bool isCSSTokenizerURL(const String& string)
   6788 {
   6789     const UChar* p = string.characters();
   6790     const UChar* end = p + string.length();
   6791 
   6792     for (; p != end; ++p) {
   6793         UChar c = p[0];
   6794         switch (c) {
   6795             case '!':
   6796             case '#':
   6797             case '$':
   6798             case '%':
   6799             case '&':
   6800                 break;
   6801             default:
   6802                 if (c < '*')
   6803                     return false;
   6804                 if (c <= '~')
   6805                     break;
   6806                 if (c < 128)
   6807                     return false;
   6808         }
   6809     }
   6810 
   6811     return true;
   6812 }
   6813 
   6814 // We use single quotes for now because markup.cpp uses double quotes.
   6815 String quoteCSSString(const String& string)
   6816 {
   6817     // For efficiency, we first pre-calculate the length of the quoted string, then we build the actual one.
   6818     // Please see below for the actual logic.
   6819     unsigned quotedStringSize = 2; // Two quotes surrounding the entire string.
   6820     bool afterEscape = false;
   6821     for (unsigned i = 0; i < string.length(); ++i) {
   6822         UChar ch = string[i];
   6823         if (ch == '\\' || ch == '\'') {
   6824             quotedStringSize += 2;
   6825             afterEscape = false;
   6826         } else if (ch < 0x20 || ch == 0x7F) {
   6827             quotedStringSize += 2 + (ch >= 0x10);
   6828             afterEscape = true;
   6829         } else {
   6830             quotedStringSize += 1 + (afterEscape && (isASCIIHexDigit(ch) || ch == ' '));
   6831             afterEscape = false;
   6832         }
   6833     }
   6834 
   6835     StringBuffer buffer(quotedStringSize);
   6836     unsigned index = 0;
   6837     buffer[index++] = '\'';
   6838     afterEscape = false;
   6839     for (unsigned i = 0; i < string.length(); ++i) {
   6840         UChar ch = string[i];
   6841         if (ch == '\\' || ch == '\'') {
   6842             buffer[index++] = '\\';
   6843             buffer[index++] = ch;
   6844             afterEscape = false;
   6845         } else if (ch < 0x20 || ch == 0x7F) { // Control characters.
   6846             buffer[index++] = '\\';
   6847             placeByteAsHexCompressIfPossible(ch, buffer, index, Lowercase);
   6848             afterEscape = true;
   6849         } else {
   6850             // Space character may be required to separate backslash-escape sequence and normal characters.
   6851             if (afterEscape && (isASCIIHexDigit(ch) || ch == ' '))
   6852                 buffer[index++] = ' ';
   6853             buffer[index++] = ch;
   6854             afterEscape = false;
   6855         }
   6856     }
   6857     buffer[index++] = '\'';
   6858 
   6859     ASSERT(quotedStringSize == index);
   6860     return String::adopt(buffer);
   6861 }
   6862 
   6863 String quoteCSSStringIfNeeded(const String& string)
   6864 {
   6865     return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string);
   6866 }
   6867 
   6868 String quoteCSSURLIfNeeded(const String& string)
   6869 {
   6870     return isCSSTokenizerURL(string) ? string : quoteCSSString(string);
   6871 }
   6872 
   6873 bool isValidNthToken(const CSSParserString& token)
   6874 {
   6875     // The tokenizer checks for the construct of an+b.
   6876     // nth can also accept "odd" or "even" but should not accept any other token.
   6877     return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even");
   6878 }
   6879 
   6880 #define YY_DECL int CSSParser::lex()
   6881 #define yyconst const
   6882 typedef int yy_state_type;
   6883 typedef unsigned YY_CHAR;
   6884 // The following line makes sure we treat non-Latin-1 Unicode characters correctly.
   6885 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
   6886 #define YY_DO_BEFORE_ACTION \
   6887         yytext = yy_bp; \
   6888         yyleng = (int) (yy_cp - yy_bp); \
   6889         yy_hold_char = *yy_cp; \
   6890         *yy_cp = 0; \
   6891         yy_c_buf_p = yy_cp;
   6892 #define YY_BREAK break;
   6893 #define ECHO
   6894 #define YY_RULE_SETUP
   6895 #define INITIAL 0
   6896 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
   6897 #define yyterminate() yyTok = END_TOKEN; return yyTok
   6898 #define YY_FATAL_ERROR(a)
   6899 // The following line is needed to build the tokenizer with a condition stack.
   6900 // The macro is used in the tokenizer grammar with lines containing
   6901 // BEGIN(mediaqueries) and BEGIN(initial). yy_start acts as index to
   6902 // tokenizer transition table, and 'mediaqueries' and 'initial' are
   6903 // offset multipliers that specify which transitions are active
   6904 // in the tokenizer during in each condition (tokenizer state).
   6905 #define BEGIN yy_start = 1 + 2 *
   6906 
   6907 #include "tokenizer.cpp"
   6908 
   6909 }
   6910