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