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