1/* 2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org) 3 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) 4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 5 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com> 6 * Copyright (C) 2008 Eric Seidel <eric@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 "CString.h" 29#include "CSSTimingFunctionValue.h" 30#include "CSSBorderImageValue.h" 31#include "CSSCanvasValue.h" 32#include "CSSCharsetRule.h" 33#include "CSSCursorImageValue.h" 34#include "CSSHelper.h" 35#include "CSSImageValue.h" 36#include "CSSFontFaceRule.h" 37#include "CSSFontFaceSrcValue.h" 38#include "CSSGradientValue.h" 39#include "CSSImportRule.h" 40#include "CSSInheritedValue.h" 41#include "CSSInitialValue.h" 42#include "CSSMediaRule.h" 43#include "CSSMutableStyleDeclaration.h" 44#include "CSSPrimitiveValue.h" 45#include "CSSProperty.h" 46#include "CSSPropertyNames.h" 47#include "CSSQuirkPrimitiveValue.h" 48#include "CSSReflectValue.h" 49#include "CSSRuleList.h" 50#include "CSSSelector.h" 51#include "CSSStyleRule.h" 52#include "CSSStyleSheet.h" 53#include "CSSUnicodeRangeValue.h" 54#include "CSSValueKeywords.h" 55#include "CSSValueList.h" 56#include "CSSVariableDependentValue.h" 57#include "CSSVariablesDeclaration.h" 58#include "CSSVariablesRule.h" 59#include "Counter.h" 60#include "Document.h" 61#include "FloatConversion.h" 62#include "FontFamilyValue.h" 63#include "FontValue.h" 64#include "MediaList.h" 65#include "MediaQueryExp.h" 66#include "Pair.h" 67#include "Rect.h" 68#include "ShadowValue.h" 69#include "WebKitCSSKeyframeRule.h" 70#include "WebKitCSSKeyframesRule.h" 71#include "WebKitCSSTransformValue.h" 72#include <wtf/dtoa.h> 73 74#if ENABLE(DASHBOARD_SUPPORT) 75#include "DashboardRegion.h" 76#endif 77 78#define YYDEBUG 0 79 80#if YYDEBUG > 0 81extern int cssyydebug; 82#endif 83 84extern int cssyyparse(void* parser); 85 86using namespace std; 87using namespace WTF; 88 89#include "CSSPropertyNames.cpp" 90#include "CSSValueKeywords.c" 91 92#ifdef ANDROID_INSTRUMENT 93#include "TimeCounter.h" 94#endif 95 96namespace WebCore { 97 98static bool equal(const CSSParserString& a, const char* b) 99{ 100 for (int i = 0; i < a.length; ++i) { 101 if (!b[i]) 102 return false; 103 if (a.characters[i] != b[i]) 104 return false; 105 } 106 return !b[a.length]; 107} 108 109static bool equalIgnoringCase(const CSSParserString& a, const char* b) 110{ 111 for (int i = 0; i < a.length; ++i) { 112 if (!b[i]) 113 return false; 114 ASSERT(!isASCIIUpper(b[i])); 115 if (toASCIILower(a.characters[i]) != b[i]) 116 return false; 117 } 118 return !b[a.length]; 119} 120 121static bool hasPrefix(const char* string, unsigned length, const char* prefix) 122{ 123 for (unsigned i = 0; i < length; ++i) { 124 if (!prefix[i]) 125 return true; 126 if (string[i] != prefix[i]) 127 return false; 128 } 129 return false; 130} 131 132CSSParser::CSSParser(bool strictParsing) 133 : m_strict(strictParsing) 134 , m_important(false) 135 , m_id(0) 136 , m_styleSheet(0) 137 , m_mediaQuery(0) 138 , m_valueList(0) 139 , m_parsedProperties(static_cast<CSSProperty**>(fastMalloc(32 * sizeof(CSSProperty*)))) 140 , m_numParsedProperties(0) 141 , m_maxParsedProperties(32) 142 , m_inParseShorthand(0) 143 , m_currentShorthand(0) 144 , m_implicitShorthand(false) 145 , m_hasFontFaceOnlyValues(false) 146 , m_hadSyntacticallyValidCSSRule(false) 147 , m_defaultNamespace(starAtom) 148 , m_data(0) 149 , yy_start(1) 150 , m_allowImportRules(true) 151 , m_allowVariablesRules(true) 152 , m_allowNamespaceDeclarations(true) 153 , m_floatingMediaQuery(0) 154 , m_floatingMediaQueryExp(0) 155 , m_floatingMediaQueryExpList(0) 156{ 157#if YYDEBUG > 0 158 cssyydebug = 1; 159#endif 160} 161 162CSSParser::~CSSParser() 163{ 164 clearProperties(); 165 fastFree(m_parsedProperties); 166 167 clearVariables(); 168 169 delete m_valueList; 170 171 fastFree(m_data); 172 173 if (m_floatingMediaQueryExpList) { 174 deleteAllValues(*m_floatingMediaQueryExpList); 175 delete m_floatingMediaQueryExpList; 176 } 177 delete m_floatingMediaQueryExp; 178 delete m_floatingMediaQuery; 179 fastDeleteAllValues(m_floatingSelectors); 180 deleteAllValues(m_floatingValueLists); 181 deleteAllValues(m_floatingFunctions); 182 deleteAllValues(m_reusableSelectorVector); 183} 184 185void CSSParserString::lower() 186{ 187 // FIXME: If we need Unicode lowercasing here, then we probably want the real kind 188 // that can potentially change the length of the string rather than the character 189 // by character kind. If we don't need Unicode lowercasing, it would be good to 190 // simplify this function. 191 192 if (charactersAreAllASCII(characters, length)) { 193 // Fast case for all-ASCII. 194 for (int i = 0; i < length; i++) 195 characters[i] = toASCIILower(characters[i]); 196 } else { 197 for (int i = 0; i < length; i++) 198 characters[i] = Unicode::toLower(characters[i]); 199 } 200} 201 202void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix) 203{ 204 int length = string.length() + strlen(prefix) + strlen(suffix) + 2; 205 206 fastFree(m_data); 207 m_data = static_cast<UChar*>(fastMalloc(length * sizeof(UChar))); 208 for (unsigned i = 0; i < strlen(prefix); i++) 209 m_data[i] = prefix[i]; 210 211 memcpy(m_data + strlen(prefix), string.characters(), string.length() * sizeof(UChar)); 212 213 unsigned start = strlen(prefix) + string.length(); 214 unsigned end = start + strlen(suffix); 215 for (unsigned i = start; i < end; i++) 216 m_data[i] = suffix[i - start]; 217 218 m_data[length - 1] = 0; 219 m_data[length - 2] = 0; 220 221 yy_hold_char = 0; 222 yyleng = 0; 223 yytext = yy_c_buf_p = m_data; 224 yy_hold_char = *yy_c_buf_p; 225} 226 227void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string) 228{ 229#ifdef ANDROID_INSTRUMENT 230 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); 231#endif 232 m_styleSheet = sheet; 233 m_defaultNamespace = starAtom; // Reset the default namespace. 234 235 setupParser("", string, ""); 236 cssyyparse(this); 237 m_rule = 0; 238#ifdef ANDROID_INSTRUMENT 239 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); 240#endif 241} 242 243PassRefPtr<CSSRule> CSSParser::parseRule(CSSStyleSheet* sheet, const String& string) 244{ 245#ifdef ANDROID_INSTRUMENT 246 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); 247#endif 248 m_styleSheet = sheet; 249 m_allowNamespaceDeclarations = false; 250 setupParser("@-webkit-rule{", string, "} "); 251 cssyyparse(this); 252#ifdef ANDROID_INSTRUMENT 253 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); 254#endif 255 return m_rule.release(); 256} 257 258PassRefPtr<CSSRule> CSSParser::parseKeyframeRule(CSSStyleSheet *sheet, const String &string) 259{ 260#ifdef ANDROID_INSTRUMENT 261 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); 262#endif 263 m_styleSheet = sheet; 264 setupParser("@-webkit-keyframe-rule{ ", string, "} "); 265 cssyyparse(this); 266#ifdef ANDROID_INSTRUMENT 267 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); 268#endif 269 return m_keyframe.release(); 270} 271 272bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int id, const String& string, bool important) 273{ 274#ifdef ANDROID_INSTRUMENT 275 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); 276#endif 277 ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet()); 278 m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet()); 279 280 setupParser("@-webkit-value{", string, "} "); 281 282 m_id = id; 283 m_important = important; 284 285 cssyyparse(this); 286 287 m_rule = 0; 288 289 bool ok = false; 290 if (m_hasFontFaceOnlyValues) 291 deleteFontFaceOnlyValues(); 292 if (m_numParsedProperties) { 293 ok = true; 294 declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties); 295 clearProperties(); 296 } 297 298#ifdef ANDROID_INSTRUMENT 299 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); 300#endif 301 return ok; 302} 303 304// color will only be changed when string contains a valid css color, making it 305// possible to set up a default color. 306bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict) 307{ 308 color = 0; 309 CSSParser parser(true); 310 311 // First try creating a color specified by name or the "#" syntax. 312 if (!parser.parseColor(string, color, strict)) { 313 RefPtr<CSSMutableStyleDeclaration> dummyStyleDeclaration = CSSMutableStyleDeclaration::create(); 314 315 // Now try to create a color from the rgb() or rgba() syntax. 316 if (parser.parseColor(dummyStyleDeclaration.get(), string)) { 317 CSSValue* value = parser.m_parsedProperties[0]->value(); 318 if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) { 319 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); 320 color = primitiveValue->getRGBA32Value(); 321 } 322 } else 323 return false; 324 } 325 326 return true; 327} 328 329bool CSSParser::parseColor(CSSMutableStyleDeclaration* declaration, const String& string) 330{ 331#ifdef ANDROID_INSTRUMENT 332 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); 333#endif 334 ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet()); 335 m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet()); 336 337 setupParser("@-webkit-decls{color:", string, "} "); 338 cssyyparse(this); 339 m_rule = 0; 340 341#ifdef ANDROID_INSTRUMENT 342 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); 343#endif 344 return (m_numParsedProperties && m_parsedProperties[0]->m_id == CSSPropertyColor); 345} 346 347void CSSParser::parseSelector(const String& string, Document* doc, CSSSelectorList& selectorList) 348{ 349#ifdef ANDROID_INSTRUMENT 350 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); 351#endif 352 RefPtr<CSSStyleSheet> dummyStyleSheet = CSSStyleSheet::create(doc); 353 354 m_styleSheet = dummyStyleSheet.get(); 355 m_selectorListForParseSelector = &selectorList; 356 357 setupParser("@-webkit-selector{", string, "}"); 358 359 cssyyparse(this); 360 361 m_selectorListForParseSelector = 0; 362#ifdef ANDROID_INSTRUMENT 363 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); 364#endif 365} 366 367bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration* declaration, const String& string) 368{ 369#ifdef ANDROID_INSTRUMENT 370 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); 371#endif 372 ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet()); 373 m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet()); 374 375 setupParser("@-webkit-decls{", string, "} "); 376 cssyyparse(this); 377 m_rule = 0; 378 379 bool ok = false; 380 if (m_hasFontFaceOnlyValues) 381 deleteFontFaceOnlyValues(); 382 if (m_numParsedProperties) { 383 ok = true; 384 declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties); 385 clearProperties(); 386 } 387 388#ifdef ANDROID_INSTRUMENT 389 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); 390#endif 391 return ok; 392} 393 394bool CSSParser::parseMediaQuery(MediaList* queries, const String& string) 395{ 396 if (string.isEmpty()) 397 return true; 398 399#ifdef ANDROID_INSTRUMENT 400 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); 401#endif 402 m_mediaQuery = 0; 403 // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token. 404 // instead insert one " " (which is WHITESPACE in CSSGrammar.y) 405 setupParser("@-webkit-mediaquery ", string, "} "); 406 cssyyparse(this); 407 408 bool ok = false; 409 if (m_mediaQuery) { 410 ok = true; 411 queries->appendMediaQuery(m_mediaQuery); 412 m_mediaQuery = 0; 413 } 414 415#ifdef ANDROID_INSTRUMENT 416 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); 417#endif 418 return ok; 419} 420 421 422void CSSParser::addProperty(int propId, PassRefPtr<CSSValue> value, bool important) 423{ 424 auto_ptr<CSSProperty> prop(new CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand)); 425 if (m_numParsedProperties >= m_maxParsedProperties) { 426 m_maxParsedProperties += 32; 427 if (m_maxParsedProperties > UINT_MAX / sizeof(CSSProperty*)) 428 return; 429 m_parsedProperties = static_cast<CSSProperty**>(fastRealloc(m_parsedProperties, 430 m_maxParsedProperties * sizeof(CSSProperty*))); 431 } 432 m_parsedProperties[m_numParsedProperties++] = prop.release(); 433} 434 435void CSSParser::rollbackLastProperties(int num) 436{ 437 ASSERT(num >= 0); 438 ASSERT(m_numParsedProperties >= static_cast<unsigned>(num)); 439 440 for (int i = 0; i < num; ++i) 441 delete m_parsedProperties[--m_numParsedProperties]; 442} 443 444void CSSParser::clearProperties() 445{ 446 for (unsigned i = 0; i < m_numParsedProperties; i++) 447 delete m_parsedProperties[i]; 448 m_numParsedProperties = 0; 449 m_hasFontFaceOnlyValues = false; 450} 451 452Document* CSSParser::document() const 453{ 454 StyleBase* root = m_styleSheet; 455 Document* doc = 0; 456 while (root && root->parent()) 457 root = root->parent(); 458 if (root && root->isCSSStyleSheet()) 459 doc = static_cast<CSSStyleSheet*>(root)->doc(); 460 return doc; 461} 462 463bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, bool strict) 464{ 465 bool b = false; 466 switch (value->unit) { 467 case CSSPrimitiveValue::CSS_NUMBER: 468 b = (unitflags & FNumber); 469 if (!b && ((unitflags & (FLength | FAngle | FTime)) && (value->fValue == 0 || !strict))) { 470 value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX : 471 ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS); 472 b = true; 473 } 474 if (!b && (unitflags & FInteger) && value->isInt) 475 b = true; 476 break; 477 case CSSPrimitiveValue::CSS_PERCENTAGE: 478 b = (unitflags & FPercent); 479 break; 480 case CSSParserValue::Q_EMS: 481 case CSSPrimitiveValue::CSS_EMS: 482 case CSSPrimitiveValue::CSS_REMS: 483 case CSSPrimitiveValue::CSS_EXS: 484 case CSSPrimitiveValue::CSS_PX: 485 case CSSPrimitiveValue::CSS_CM: 486 case CSSPrimitiveValue::CSS_MM: 487 case CSSPrimitiveValue::CSS_IN: 488 case CSSPrimitiveValue::CSS_PT: 489 case CSSPrimitiveValue::CSS_PC: 490 b = (unitflags & FLength); 491 break; 492 case CSSPrimitiveValue::CSS_MS: 493 case CSSPrimitiveValue::CSS_S: 494 b = (unitflags & FTime); 495 break; 496 case CSSPrimitiveValue::CSS_DEG: 497 case CSSPrimitiveValue::CSS_RAD: 498 case CSSPrimitiveValue::CSS_GRAD: 499 case CSSPrimitiveValue::CSS_TURN: 500 b = (unitflags & FAngle); 501 break; 502 case CSSPrimitiveValue::CSS_HZ: 503 case CSSPrimitiveValue::CSS_KHZ: 504 case CSSPrimitiveValue::CSS_DIMENSION: 505 default: 506 break; 507 } 508 if (b && unitflags & FNonNeg && value->fValue < 0) 509 b = false; 510 return b; 511} 512 513static int unitFromString(CSSParserValue* value) 514{ 515 if (value->unit != CSSPrimitiveValue::CSS_IDENT || value->id) 516 return 0; 517 518 if (equal(value->string, "em")) 519 return CSSPrimitiveValue::CSS_EMS; 520 if (equal(value->string, "rem")) 521 return CSSPrimitiveValue::CSS_REMS; 522 if (equal(value->string, "ex")) 523 return CSSPrimitiveValue::CSS_EXS; 524 if (equal(value->string, "px")) 525 return CSSPrimitiveValue::CSS_PX; 526 if (equal(value->string, "cm")) 527 return CSSPrimitiveValue::CSS_CM; 528 if (equal(value->string, "mm")) 529 return CSSPrimitiveValue::CSS_MM; 530 if (equal(value->string, "in")) 531 return CSSPrimitiveValue::CSS_IN; 532 if (equal(value->string, "pt")) 533 return CSSPrimitiveValue::CSS_PT; 534 if (equal(value->string, "pc")) 535 return CSSPrimitiveValue::CSS_PC; 536 if (equal(value->string, "deg")) 537 return CSSPrimitiveValue::CSS_DEG; 538 if (equal(value->string, "rad")) 539 return CSSPrimitiveValue::CSS_RAD; 540 if (equal(value->string, "grad")) 541 return CSSPrimitiveValue::CSS_GRAD; 542 if (equal(value->string, "turn")) 543 return CSSPrimitiveValue::CSS_TURN; 544 if (equal(value->string, "ms")) 545 return CSSPrimitiveValue::CSS_MS; 546 if (equal(value->string, "s")) 547 return CSSPrimitiveValue::CSS_S; 548 if (equal(value->string, "Hz")) 549 return CSSPrimitiveValue::CSS_HZ; 550 if (equal(value->string, "kHz")) 551 return CSSPrimitiveValue::CSS_KHZ; 552 553 return 0; 554} 555 556void CSSParser::checkForOrphanedUnits() 557{ 558 if (m_strict || inShorthand()) 559 return; 560 561 // The purpose of this code is to implement the WinIE quirk that allows unit types to be separated from their numeric values 562 // 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. 563 CSSParserValue* numericVal = 0; 564 unsigned size = m_valueList->size(); 565 for (unsigned i = 0; i < size; i++) { 566 CSSParserValue* value = m_valueList->valueAt(i); 567 568 if (numericVal) { 569 // Change the unit type of the numeric val to match. 570 int unit = unitFromString(value); 571 if (unit) { 572 numericVal->unit = unit; 573 numericVal = 0; 574 575 // Now delete the bogus unit value. 576 m_valueList->deleteValueAt(i); 577 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). 578 size--; 579 continue; 580 } 581 } 582 583 numericVal = (value->unit == CSSPrimitiveValue::CSS_NUMBER) ? value : 0; 584 } 585} 586 587bool CSSParser::parseValue(int propId, bool important) 588{ 589 if (!m_valueList) 590 return false; 591 592 CSSParserValue *value = m_valueList->current(); 593 594 if (!value) 595 return false; 596 597 int id = value->id; 598 599 // In quirks mode, we will look for units that have been incorrectly separated from the number they belong to 600 // by a space. We go ahead and associate the unit with the number even though it is invalid CSS. 601 checkForOrphanedUnits(); 602 603 int num = inShorthand() ? 1 : m_valueList->size(); 604 605 if (id == CSSValueInherit) { 606 if (num != 1) 607 return false; 608 addProperty(propId, CSSInheritedValue::create(), important); 609 return true; 610 } 611 else if (id == CSSValueInitial) { 612 if (num != 1) 613 return false; 614 addProperty(propId, CSSInitialValue::createExplicit(), important); 615 return true; 616 } 617 618 // If we have any variables, then we don't parse the list of values yet. We add them to the declaration 619 // as unresolved, and allow them to be parsed later. The parse is considered "successful" for now, even though 620 // it might ultimately fail once the variable has been resolved. 621 if (!inShorthand() && checkForVariables(m_valueList)) { 622 addUnresolvedProperty(propId, important); 623 return true; 624 } 625 626 bool validPrimitive = false; 627 RefPtr<CSSValue> parsedValue; 628 629 switch (static_cast<CSSPropertyID>(propId)) { 630 /* The comment to the left defines all valid value of this properties as defined 631 * in CSS 2, Appendix F. Property index 632 */ 633 634 /* All the CSS properties are not supported by the renderer at the moment. 635 * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined 636 * (see parseAuralValues). As we don't support them at all this seems reasonable. 637 */ 638 639 case CSSPropertySize: // <length>{1,2} | auto | portrait | landscape | inherit 640 case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit 641 if (id) 642 validPrimitive = true; 643 break; 644 case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | inherit 645 if (id == CSSValueNormal || 646 id == CSSValueEmbed || 647 id == CSSValueBidiOverride) 648 validPrimitive = true; 649 break; 650 651 case CSSPropertyPosition: // static | relative | absolute | fixed | inherit 652 if (id == CSSValueStatic || 653 id == CSSValueRelative || 654 id == CSSValueAbsolute || 655 id == CSSValueFixed) 656 validPrimitive = true; 657 break; 658 659 case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit 660 case CSSPropertyPageBreakBefore: 661 case CSSPropertyWebkitColumnBreakAfter: 662 case CSSPropertyWebkitColumnBreakBefore: 663 if (id == CSSValueAuto || 664 id == CSSValueAlways || 665 id == CSSValueAvoid || 666 id == CSSValueLeft || 667 id == CSSValueRight) 668 validPrimitive = true; 669 break; 670 671 case CSSPropertyPageBreakInside: // avoid | auto | inherit 672 case CSSPropertyWebkitColumnBreakInside: 673 if (id == CSSValueAuto || id == CSSValueAvoid) 674 validPrimitive = true; 675 break; 676 677 case CSSPropertyEmptyCells: // show | hide | inherit 678 if (id == CSSValueShow || 679 id == CSSValueHide) 680 validPrimitive = true; 681 break; 682 683 case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote | 684 // close-quote | no-open-quote | no-close-quote ]+ | inherit 685 return parseContent(propId, important); 686 687 case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit 688 if (id == CSSValueNormal || 689 id == CSSValuePre || 690 id == CSSValuePreWrap || 691 id == CSSValuePreLine || 692 id == CSSValueNowrap) 693 validPrimitive = true; 694 break; 695 696 case CSSPropertyClip: // <shape> | auto | inherit 697 if (id == CSSValueAuto) 698 validPrimitive = true; 699 else if (value->unit == CSSParserValue::Function) 700 return parseShape(propId, important); 701 break; 702 703 /* Start of supported CSS properties with validation. This is needed for parseShorthand to work 704 * correctly and allows optimization in WebCore::applyRule(..) 705 */ 706 case CSSPropertyCaptionSide: // top | bottom | left | right | inherit 707 if (id == CSSValueLeft || id == CSSValueRight || 708 id == CSSValueTop || id == CSSValueBottom) 709 validPrimitive = true; 710 break; 711 712 case CSSPropertyBorderCollapse: // collapse | separate | inherit 713 if (id == CSSValueCollapse || id == CSSValueSeparate) 714 validPrimitive = true; 715 break; 716 717 case CSSPropertyVisibility: // visible | hidden | collapse | inherit 718 if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueCollapse) 719 validPrimitive = true; 720 break; 721 722 case CSSPropertyOverflow: { 723 ShorthandScope scope(this, propId); 724 if (num != 1 || !parseValue(CSSPropertyOverflowX, important)) 725 return false; 726 CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value(); 727 addProperty(CSSPropertyOverflowY, value, important); 728 return true; 729 } 730 case CSSPropertyOverflowX: 731 case CSSPropertyOverflowY: // visible | hidden | scroll | auto | marquee | overlay | inherit 732 if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueScroll || id == CSSValueAuto || 733 id == CSSValueOverlay || id == CSSValueWebkitMarquee) 734 validPrimitive = true; 735 break; 736 737 case CSSPropertyListStylePosition: // inside | outside | inherit 738 if (id == CSSValueInside || id == CSSValueOutside) 739 validPrimitive = true; 740 break; 741 742 case CSSPropertyListStyleType: 743 // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in 744 // for the list of supported list-style-types. 745 if ((id >= CSSValueDisc && id <= CSSValueKatakanaIroha) || id == CSSValueNone) 746 validPrimitive = true; 747 break; 748 749 case CSSPropertyDisplay: 750 // inline | block | list-item | run-in | inline-block | table | 751 // inline-table | table-row-group | table-header-group | table-footer-group | table-row | 752 // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit 753#if ENABLE(WCSS) 754 if ((id >= CSSValueInline && id <= CSSValueWapMarquee) || id == CSSValueNone) 755#else 756 if ((id >= CSSValueInline && id <= CSSValueWebkitInlineBox) || id == CSSValueNone) 757#endif 758 validPrimitive = true; 759 break; 760 761 case CSSPropertyDirection: // ltr | rtl | inherit 762 if (id == CSSValueLtr || id == CSSValueRtl) 763 validPrimitive = true; 764 break; 765 766 case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit 767 if ((id >= CSSValueCapitalize && id <= CSSValueLowercase) || id == CSSValueNone) 768 validPrimitive = true; 769 break; 770 771 case CSSPropertyFloat: // left | right | none | inherit + center for buggy CSS 772 if (id == CSSValueLeft || id == CSSValueRight || 773 id == CSSValueNone || id == CSSValueCenter) 774 validPrimitive = true; 775 break; 776 777 case CSSPropertyClear: // none | left | right | both | inherit 778 if (id == CSSValueNone || id == CSSValueLeft || 779 id == CSSValueRight|| id == CSSValueBoth) 780 validPrimitive = true; 781 break; 782 783 case CSSPropertyTextAlign: 784 // left | right | center | justify | webkit_left | webkit_right | webkit_center | start | end | <string> | inherit 785 if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitCenter) || id == CSSValueStart || id == CSSValueEnd || 786 value->unit == CSSPrimitiveValue::CSS_STRING) 787 validPrimitive = true; 788 break; 789 790 case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit 791 if (id == CSSValueAuto || id == CSSValueNone || (id >= CSSValueInset && id <= CSSValueDouble)) 792 validPrimitive = true; 793 break; 794 795 case CSSPropertyBorderTopStyle: //// <border-style> | inherit 796 case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed | 797 case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset 798 case CSSPropertyBorderLeftStyle: 799 case CSSPropertyWebkitColumnRuleStyle: 800 if (id >= CSSValueNone && id <= CSSValueDouble) 801 validPrimitive = true; 802 break; 803 804 case CSSPropertyFontWeight: // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit 805 return parseFontWeight(important); 806 807 case CSSPropertyBorderSpacing: { 808 const int properties[2] = { CSSPropertyWebkitBorderHorizontalSpacing, 809 CSSPropertyWebkitBorderVerticalSpacing }; 810 if (num == 1) { 811 ShorthandScope scope(this, CSSPropertyBorderSpacing); 812 if (!parseValue(properties[0], important)) 813 return false; 814 CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value(); 815 addProperty(properties[1], value, important); 816 return true; 817 } 818 else if (num == 2) { 819 ShorthandScope scope(this, CSSPropertyBorderSpacing); 820 if (!parseValue(properties[0], important) || !parseValue(properties[1], important)) 821 return false; 822 return true; 823 } 824 return false; 825 } 826 case CSSPropertyWebkitBorderHorizontalSpacing: 827 case CSSPropertyWebkitBorderVerticalSpacing: 828 validPrimitive = validUnit(value, FLength | FNonNeg, m_strict); 829 break; 830 case CSSPropertyOutlineColor: // <color> | invert | inherit 831 // Outline color has "invert" as additional keyword. 832 // Also, we want to allow the special focus color even in strict parsing mode. 833 if (propId == CSSPropertyOutlineColor && (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor)) { 834 validPrimitive = true; 835 break; 836 } 837 /* nobreak */ 838 case CSSPropertyBackgroundColor: // <color> | inherit 839 case CSSPropertyBorderTopColor: // <color> | inherit 840 case CSSPropertyBorderRightColor: // <color> | inherit 841 case CSSPropertyBorderBottomColor: // <color> | inherit 842 case CSSPropertyBorderLeftColor: // <color> | inherit 843 case CSSPropertyColor: // <color> | inherit 844 case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors 845 case CSSPropertyTextUnderlineColor: 846 case CSSPropertyTextOverlineColor: 847 case CSSPropertyWebkitColumnRuleColor: 848 case CSSPropertyWebkitTextFillColor: 849 case CSSPropertyWebkitTextStrokeColor: 850 if (id == CSSValueWebkitText) 851 validPrimitive = true; // Always allow this, even when strict parsing is on, 852 // since we use this in our UA sheets. 853 else if (id == CSSValueCurrentcolor) 854 validPrimitive = true; 855 else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || 856 (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && !m_strict)) { 857 validPrimitive = true; 858 } else { 859 parsedValue = parseColor(); 860 if (parsedValue) 861 m_valueList->next(); 862 } 863 break; 864 865 case CSSPropertyCursor: { 866 // [<uri>,]* [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize | 867 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize | 868 // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help | 869 // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in 870 // -webkit-zoom-in | -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit 871 RefPtr<CSSValueList> list; 872 while (value && value->unit == CSSPrimitiveValue::CSS_URI) { 873 if (!list) 874 list = CSSValueList::createCommaSeparated(); 875 String uri = value->string; 876 Vector<int> coords; 877 value = m_valueList->next(); 878 while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) { 879 coords.append(int(value->fValue)); 880 value = m_valueList->next(); 881 } 882 IntPoint hotspot; 883 int nrcoords = coords.size(); 884 if (nrcoords > 0 && nrcoords != 2) 885 return false; 886 if (nrcoords == 2) 887 hotspot = IntPoint(coords[0], coords[1]); 888 889 if (!uri.isNull() && m_styleSheet) { 890 // FIXME: The completeURL call should be done when using the CSSCursorImageValue, 891 // not when creating it. 892 list->append(CSSCursorImageValue::create(m_styleSheet->completeURL(uri), hotspot)); 893 } 894 895 if ((m_strict && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ','))) 896 return false; 897 value = m_valueList->next(); // comma 898 } 899 if (list) { 900 if (!value) { // no value after url list (MSIE 5 compatibility) 901 if (list->length() != 1) 902 return false; 903 } else if (!m_strict && value->id == CSSValueHand) // MSIE 5 compatibility :/ 904 list->append(CSSPrimitiveValue::createIdentifier(CSSValuePointer)); 905 else if (value && ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)) 906 list->append(CSSPrimitiveValue::createIdentifier(value->id)); 907 m_valueList->next(); 908 parsedValue = list.release(); 909 break; 910 } 911 id = value->id; 912 if (!m_strict && value->id == CSSValueHand) { // MSIE 5 compatibility :/ 913 id = CSSValuePointer; 914 validPrimitive = true; 915 } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone) 916 validPrimitive = true; 917 break; 918 } 919 920 case CSSPropertyBackgroundAttachment: 921 case CSSPropertyBackgroundClip: 922 case CSSPropertyWebkitBackgroundClip: 923 case CSSPropertyWebkitBackgroundComposite: 924 case CSSPropertyBackgroundImage: 925 case CSSPropertyBackgroundOrigin: 926 case CSSPropertyWebkitBackgroundOrigin: 927 case CSSPropertyBackgroundPosition: 928 case CSSPropertyBackgroundPositionX: 929 case CSSPropertyBackgroundPositionY: 930 case CSSPropertyBackgroundSize: 931 case CSSPropertyWebkitBackgroundSize: 932 case CSSPropertyBackgroundRepeat: 933 case CSSPropertyBackgroundRepeatX: 934 case CSSPropertyBackgroundRepeatY: 935 case CSSPropertyWebkitMaskAttachment: 936 case CSSPropertyWebkitMaskClip: 937 case CSSPropertyWebkitMaskComposite: 938 case CSSPropertyWebkitMaskImage: 939 case CSSPropertyWebkitMaskOrigin: 940 case CSSPropertyWebkitMaskPosition: 941 case CSSPropertyWebkitMaskPositionX: 942 case CSSPropertyWebkitMaskPositionY: 943 case CSSPropertyWebkitMaskSize: 944 case CSSPropertyWebkitMaskRepeat: 945 case CSSPropertyWebkitMaskRepeatX: 946 case CSSPropertyWebkitMaskRepeatY: { 947 RefPtr<CSSValue> val1; 948 RefPtr<CSSValue> val2; 949 int propId1, propId2; 950 bool result = false; 951 if (parseFillProperty(propId, propId1, propId2, val1, val2)) { 952 OwnPtr<ShorthandScope> shorthandScope; 953 if (propId == CSSPropertyBackgroundPosition || 954 propId == CSSPropertyBackgroundRepeat || 955 propId == CSSPropertyWebkitMaskPosition || 956 propId == CSSPropertyWebkitMaskRepeat) { 957 shorthandScope.set(new ShorthandScope(this, propId)); 958 } 959 addProperty(propId1, val1.release(), important); 960 if (val2) 961 addProperty(propId2, val2.release(), important); 962 result = true; 963 } 964 m_implicitShorthand = false; 965 return result; 966 } 967 case CSSPropertyListStyleImage: // <uri> | none | inherit 968 if (id == CSSValueNone) { 969 parsedValue = CSSImageValue::create(); 970 m_valueList->next(); 971 } else if (value->unit == CSSPrimitiveValue::CSS_URI) { 972 if (m_styleSheet) { 973 // FIXME: The completeURL call should be done when using the CSSImageValue, 974 // not when creating it. 975 parsedValue = CSSImageValue::create(m_styleSheet->completeURL(value->string)); 976 m_valueList->next(); 977 } 978 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-gradient(")) { 979 if (parseGradient(parsedValue)) 980 m_valueList->next(); 981 else 982 return false; 983 } 984 break; 985 986 case CSSPropertyWebkitTextStrokeWidth: 987 case CSSPropertyOutlineWidth: // <border-width> | inherit 988 case CSSPropertyBorderTopWidth: //// <border-width> | inherit 989 case CSSPropertyBorderRightWidth: // Which is defined as 990 case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length> 991 case CSSPropertyBorderLeftWidth: 992 case CSSPropertyWebkitColumnRuleWidth: 993 if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick) 994 validPrimitive = true; 995 else 996 validPrimitive = validUnit(value, FLength, m_strict); 997 break; 998 999 case CSSPropertyLetterSpacing: // normal | <length> | inherit 1000 case CSSPropertyWordSpacing: // normal | <length> | inherit 1001 if (id == CSSValueNormal) 1002 validPrimitive = true; 1003 else 1004 validPrimitive = validUnit(value, FLength, m_strict); 1005 break; 1006 1007 case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension) 1008 if (id == CSSValueNormal || id == CSSValueBreakAll || id == CSSValueBreakWord) 1009 validPrimitive = true; 1010 break; 1011 1012 case CSSPropertyWordWrap: // normal | break-word 1013 if (id == CSSValueNormal || id == CSSValueBreakWord) 1014 validPrimitive = true; 1015 break; 1016 1017 case CSSPropertyTextIndent: // <length> | <percentage> | inherit 1018 case CSSPropertyPaddingTop: //// <padding-width> | inherit 1019 case CSSPropertyPaddingRight: // Which is defined as 1020 case CSSPropertyPaddingBottom: // <length> | <percentage> 1021 case CSSPropertyPaddingLeft: //// 1022 case CSSPropertyWebkitPaddingStart: 1023 validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict)); 1024 break; 1025 1026 case CSSPropertyMaxHeight: // <length> | <percentage> | none | inherit 1027 case CSSPropertyMaxWidth: // <length> | <percentage> | none | inherit 1028 if (id == CSSValueNone || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) { 1029 validPrimitive = true; 1030 break; 1031 } 1032 /* nobreak */ 1033 case CSSPropertyMinHeight: // <length> | <percentage> | inherit 1034 case CSSPropertyMinWidth: // <length> | <percentage> | inherit 1035 if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) 1036 validPrimitive = true; 1037 else 1038 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict)); 1039 break; 1040 1041 case CSSPropertyFontSize: 1042 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit 1043 if (id >= CSSValueXxSmall && id <= CSSValueLarger) 1044 validPrimitive = true; 1045 else 1046 validPrimitive = (validUnit(value, FLength | FPercent | FNonNeg, m_strict)); 1047 break; 1048 1049 case CSSPropertyFontStyle: // normal | italic | oblique | inherit 1050 return parseFontStyle(important); 1051 1052 case CSSPropertyFontVariant: // normal | small-caps | inherit 1053 return parseFontVariant(important); 1054 1055 case CSSPropertyVerticalAlign: 1056 // baseline | sub | super | top | text-top | middle | bottom | text-bottom | 1057 // <percentage> | <length> | inherit 1058 1059 if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle) 1060 validPrimitive = true; 1061 else 1062 validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict)); 1063 break; 1064 1065 case CSSPropertyHeight: // <length> | <percentage> | auto | inherit 1066 case CSSPropertyWidth: // <length> | <percentage> | auto | inherit 1067 if (id == CSSValueAuto || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) 1068 validPrimitive = true; 1069 else 1070 // ### handle multilength case where we allow relative units 1071 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict)); 1072 break; 1073 1074 case CSSPropertyBottom: // <length> | <percentage> | auto | inherit 1075 case CSSPropertyLeft: // <length> | <percentage> | auto | inherit 1076 case CSSPropertyRight: // <length> | <percentage> | auto | inherit 1077 case CSSPropertyTop: // <length> | <percentage> | auto | inherit 1078 case CSSPropertyMarginTop: //// <margin-width> | inherit 1079 case CSSPropertyMarginRight: // Which is defined as 1080 case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit 1081 case CSSPropertyMarginLeft: //// 1082 case CSSPropertyWebkitMarginStart: 1083 if (id == CSSValueAuto) 1084 validPrimitive = true; 1085 else 1086 validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict)); 1087 break; 1088 1089 case CSSPropertyZIndex: // auto | <integer> | inherit 1090 if (id == CSSValueAuto) { 1091 validPrimitive = true; 1092 break; 1093 } 1094 /* nobreak */ 1095 case CSSPropertyOrphans: // <integer> | inherit 1096 case CSSPropertyWidows: // <integer> | inherit 1097 // ### not supported later on 1098 validPrimitive = (!id && validUnit(value, FInteger, false)); 1099 break; 1100 1101 case CSSPropertyLineHeight: // normal | <number> | <length> | <percentage> | inherit 1102 if (id == CSSValueNormal) 1103 validPrimitive = true; 1104 else 1105 validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict)); 1106 break; 1107 case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit 1108 if (id != CSSValueNone) 1109 return parseCounter(propId, 1, important); 1110 validPrimitive = true; 1111 break; 1112 case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit 1113 if (id != CSSValueNone) 1114 return parseCounter(propId, 0, important); 1115 validPrimitive = true; 1116 break; 1117 case CSSPropertyFontFamily: 1118 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit 1119 { 1120 parsedValue = parseFontFamily(); 1121 break; 1122 } 1123 1124 case CSSPropertyTextDecoration: 1125 case CSSPropertyWebkitTextDecorationsInEffect: 1126 // none | [ underline || overline || line-through || blink ] | inherit 1127 if (id == CSSValueNone) { 1128 validPrimitive = true; 1129 } else { 1130 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); 1131 bool isValid = true; 1132 while (isValid && value) { 1133 switch (value->id) { 1134 case CSSValueBlink: 1135 break; 1136 case CSSValueUnderline: 1137 case CSSValueOverline: 1138 case CSSValueLineThrough: 1139 list->append(CSSPrimitiveValue::createIdentifier(value->id)); 1140 break; 1141 default: 1142 isValid = false; 1143 } 1144 value = m_valueList->next(); 1145 } 1146 if (list->length() && isValid) { 1147 parsedValue = list.release(); 1148 m_valueList->next(); 1149 } 1150 } 1151 break; 1152 1153 case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit 1154 if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument) 1155 validPrimitive = true; 1156 else 1157 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, true)); 1158 break; 1159 1160 case CSSPropertyTableLayout: // auto | fixed | inherit 1161 if (id == CSSValueAuto || id == CSSValueFixed) 1162 validPrimitive = true; 1163 break; 1164 1165 case CSSPropertySrc: // Only used within @font-face, so cannot use inherit | initial or be !important. This is a list of urls or local references. 1166 return parseFontFaceSrc(); 1167 1168 case CSSPropertyUnicodeRange: 1169 return parseFontFaceUnicodeRange(); 1170 1171 /* CSS3 properties */ 1172 case CSSPropertyWebkitAppearance: 1173 if ((id >= CSSValueCheckbox && id <= CSSValueTextarea) || id == CSSValueNone) 1174 validPrimitive = true; 1175 break; 1176 1177 case CSSPropertyWebkitBinding: 1178#if ENABLE(XBL) 1179 if (id == CSSValueNone) 1180 validPrimitive = true; 1181 else { 1182 RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated(); 1183 CSSParserValue* val; 1184 RefPtr<CSSValue> parsedValue; 1185 while ((val = m_valueList->current())) { 1186 if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) { 1187 // FIXME: The completeURL call should be done when using the CSSPrimitiveValue, 1188 // not when creating it. 1189 parsedValue = CSSPrimitiveValue::create(m_styleSheet->completeURL(val->string), CSSPrimitiveValue::CSS_URI); 1190 } 1191 if (!parsedValue) 1192 break; 1193 1194 // FIXME: We can't use release() here since we might hit this path twice 1195 // but that logic seems wrong to me to begin with, we convert all non-uri values 1196 // into the last seen URI value!? 1197 // -webkit-binding: url(foo.xml), 1, 2; (if that were valid) is treated as: 1198 // -webkit-binding: url(foo.xml), url(foo.xml), url(foo.xml); !? 1199 values->append(parsedValue.get()); 1200 m_valueList->next(); 1201 } 1202 if (!values->length()) 1203 return false; 1204 1205 addProperty(propId, values.release(), important); 1206 m_valueList->next(); 1207 return true; 1208 } 1209#endif 1210 break; 1211 case CSSPropertyWebkitBorderImage: 1212 case CSSPropertyWebkitMaskBoxImage: 1213 if (id == CSSValueNone) 1214 validPrimitive = true; 1215 else { 1216 RefPtr<CSSValue> result; 1217 if (parseBorderImage(propId, important, result)) { 1218 addProperty(propId, result, important); 1219 return true; 1220 } 1221 } 1222 break; 1223 case CSSPropertyBorderTopRightRadius: 1224 case CSSPropertyBorderTopLeftRadius: 1225 case CSSPropertyBorderBottomLeftRadius: 1226 case CSSPropertyBorderBottomRightRadius: { 1227 if (num != 1 && num != 2) 1228 return false; 1229 validPrimitive = validUnit(value, FLength, m_strict); 1230 if (!validPrimitive) 1231 return false; 1232 RefPtr<CSSPrimitiveValue> parsedValue1 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); 1233 RefPtr<CSSPrimitiveValue> parsedValue2; 1234 if (num == 2) { 1235 value = m_valueList->next(); 1236 validPrimitive = validUnit(value, FLength, m_strict); 1237 if (!validPrimitive) 1238 return false; 1239 parsedValue2 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); 1240 } else 1241 parsedValue2 = parsedValue1; 1242 1243 RefPtr<Pair> pair = Pair::create(parsedValue1.release(), parsedValue2.release()); 1244 RefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(pair.release()); 1245 addProperty(propId, val.release(), important); 1246 return true; 1247 } 1248 case CSSPropertyBorderRadius: 1249 case CSSPropertyWebkitBorderRadius: 1250 return parseBorderRadius(propId, important); 1251 case CSSPropertyOutlineOffset: 1252 validPrimitive = validUnit(value, FLength, m_strict); 1253 break; 1254 case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3 1255 case CSSPropertyWebkitBoxShadow: 1256 if (id == CSSValueNone) 1257 validPrimitive = true; 1258 else 1259 return parseShadow(propId, important); 1260 break; 1261 case CSSPropertyWebkitBoxReflect: 1262 if (id == CSSValueNone) 1263 validPrimitive = true; 1264 else 1265 return parseReflect(propId, important); 1266 break; 1267 case CSSPropertyOpacity: 1268 validPrimitive = validUnit(value, FNumber, m_strict); 1269 break; 1270 case CSSPropertyWebkitBoxAlign: 1271 if (id == CSSValueStretch || id == CSSValueStart || id == CSSValueEnd || 1272 id == CSSValueCenter || id == CSSValueBaseline) 1273 validPrimitive = true; 1274 break; 1275 case CSSPropertyWebkitBoxDirection: 1276 if (id == CSSValueNormal || id == CSSValueReverse) 1277 validPrimitive = true; 1278 break; 1279 case CSSPropertyWebkitBoxLines: 1280 if (id == CSSValueSingle || id == CSSValueMultiple) 1281 validPrimitive = true; 1282 break; 1283 case CSSPropertyWebkitBoxOrient: 1284 if (id == CSSValueHorizontal || id == CSSValueVertical || 1285 id == CSSValueInlineAxis || id == CSSValueBlockAxis) 1286 validPrimitive = true; 1287 break; 1288 case CSSPropertyWebkitBoxPack: 1289 if (id == CSSValueStart || id == CSSValueEnd || 1290 id == CSSValueCenter || id == CSSValueJustify) 1291 validPrimitive = true; 1292 break; 1293 case CSSPropertyWebkitBoxFlex: 1294 validPrimitive = validUnit(value, FNumber, m_strict); 1295 break; 1296 case CSSPropertyWebkitBoxFlexGroup: 1297 case CSSPropertyWebkitBoxOrdinalGroup: 1298 validPrimitive = validUnit(value, FInteger | FNonNeg, true); 1299 break; 1300 case CSSPropertyWebkitBoxSizing: 1301 validPrimitive = id == CSSValueBorderBox || id == CSSValueContentBox; 1302 break; 1303 case CSSPropertyWebkitColorCorrection: 1304 validPrimitive = id == CSSValueSrgb || id == CSSValueDefault; 1305 break; 1306 case CSSPropertyWebkitMarquee: { 1307 const int properties[5] = { CSSPropertyWebkitMarqueeDirection, CSSPropertyWebkitMarqueeIncrement, 1308 CSSPropertyWebkitMarqueeRepetition, 1309 CSSPropertyWebkitMarqueeStyle, CSSPropertyWebkitMarqueeSpeed }; 1310 return parseShorthand(propId, properties, 5, important); 1311 } 1312 case CSSPropertyWebkitMarqueeDirection: 1313 if (id == CSSValueForwards || id == CSSValueBackwards || id == CSSValueAhead || 1314 id == CSSValueReverse || id == CSSValueLeft || id == CSSValueRight || id == CSSValueDown || 1315 id == CSSValueUp || id == CSSValueAuto) 1316 validPrimitive = true; 1317 break; 1318 case CSSPropertyWebkitMarqueeIncrement: 1319 if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium) 1320 validPrimitive = true; 1321 else 1322 validPrimitive = validUnit(value, FLength | FPercent, m_strict); 1323 break; 1324 case CSSPropertyWebkitMarqueeStyle: 1325 if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate) 1326 validPrimitive = true; 1327 break; 1328 case CSSPropertyWebkitMarqueeRepetition: 1329 if (id == CSSValueInfinite) 1330 validPrimitive = true; 1331 else 1332 validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict); 1333 break; 1334 case CSSPropertyWebkitMarqueeSpeed: 1335 if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast) 1336 validPrimitive = true; 1337 else 1338 validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict); 1339 break; 1340#if ENABLE(WCSS) 1341 case CSSPropertyWapMarqueeDir: 1342 if (id == CSSValueLtr || id == CSSValueRtl) 1343 validPrimitive = true; 1344 break; 1345 case CSSPropertyWapMarqueeStyle: 1346 if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate) 1347 validPrimitive = true; 1348 break; 1349 case CSSPropertyWapMarqueeLoop: 1350 if (id == CSSValueInfinite) 1351 validPrimitive = true; 1352 else 1353 validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict); 1354 break; 1355 case CSSPropertyWapMarqueeSpeed: 1356 if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast) 1357 validPrimitive = true; 1358 else 1359 validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict); 1360 break; 1361#endif 1362 case CSSPropertyWebkitUserDrag: // auto | none | element 1363 if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueElement) 1364 validPrimitive = true; 1365 break; 1366 case CSSPropertyWebkitUserModify: // read-only | read-write 1367 if (id == CSSValueReadOnly || id == CSSValueReadWrite || id == CSSValueReadWritePlaintextOnly) 1368 validPrimitive = true; 1369 break; 1370 case CSSPropertyWebkitUserSelect: // auto | none | text 1371 if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueText) 1372 validPrimitive = true; 1373 break; 1374 case CSSPropertyTextOverflow: // clip | ellipsis 1375 if (id == CSSValueClip || id == CSSValueEllipsis) 1376 validPrimitive = true; 1377 break; 1378 case CSSPropertyWebkitTransform: 1379 if (id == CSSValueNone) 1380 validPrimitive = true; 1381 else { 1382 PassRefPtr<CSSValue> val = parseTransform(); 1383 if (val) { 1384 addProperty(propId, val, important); 1385 return true; 1386 } 1387 return false; 1388 } 1389 break; 1390 case CSSPropertyWebkitTransformOrigin: 1391 case CSSPropertyWebkitTransformOriginX: 1392 case CSSPropertyWebkitTransformOriginY: 1393 case CSSPropertyWebkitTransformOriginZ: { 1394 RefPtr<CSSValue> val1; 1395 RefPtr<CSSValue> val2; 1396 RefPtr<CSSValue> val3; 1397 int propId1, propId2, propId3; 1398 if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) { 1399 addProperty(propId1, val1.release(), important); 1400 if (val2) 1401 addProperty(propId2, val2.release(), important); 1402 if (val3) 1403 addProperty(propId3, val3.release(), important); 1404 return true; 1405 } 1406 return false; 1407 } 1408 case CSSPropertyWebkitTransformStyle: 1409 if (value->id == CSSValueFlat || value->id == CSSValuePreserve3d) 1410 validPrimitive = true; 1411 break; 1412 case CSSPropertyWebkitBackfaceVisibility: 1413 if (value->id == CSSValueVisible || value->id == CSSValueHidden) 1414 validPrimitive = true; 1415 break; 1416 case CSSPropertyWebkitPerspective: 1417 if (id == CSSValueNone) 1418 validPrimitive = true; 1419 else { 1420 // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property. 1421 if (validUnit(value, FNumber | FLength | FNonNeg, m_strict)) { 1422 RefPtr<CSSValue> val = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); 1423 if (val) { 1424 addProperty(propId, val.release(), important); 1425 return true; 1426 } 1427 return false; 1428 } 1429 } 1430 break; 1431 case CSSPropertyWebkitPerspectiveOrigin: 1432 case CSSPropertyWebkitPerspectiveOriginX: 1433 case CSSPropertyWebkitPerspectiveOriginY: { 1434 RefPtr<CSSValue> val1; 1435 RefPtr<CSSValue> val2; 1436 int propId1, propId2; 1437 if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) { 1438 addProperty(propId1, val1.release(), important); 1439 if (val2) 1440 addProperty(propId2, val2.release(), important); 1441 return true; 1442 } 1443 return false; 1444 } 1445 case CSSPropertyWebkitAnimationDelay: 1446 case CSSPropertyWebkitAnimationDirection: 1447 case CSSPropertyWebkitAnimationDuration: 1448 case CSSPropertyWebkitAnimationName: 1449 case CSSPropertyWebkitAnimationPlayState: 1450 case CSSPropertyWebkitAnimationIterationCount: 1451 case CSSPropertyWebkitAnimationTimingFunction: 1452 case CSSPropertyWebkitTransitionDelay: 1453 case CSSPropertyWebkitTransitionDuration: 1454 case CSSPropertyWebkitTransitionTimingFunction: 1455 case CSSPropertyWebkitTransitionProperty: { 1456 RefPtr<CSSValue> val; 1457 if (parseAnimationProperty(propId, val)) { 1458 addProperty(propId, val.release(), important); 1459 return true; 1460 } 1461 return false; 1462 } 1463 case CSSPropertyWebkitMarginCollapse: { 1464 const int properties[2] = { CSSPropertyWebkitMarginTopCollapse, 1465 CSSPropertyWebkitMarginBottomCollapse }; 1466 if (num == 1) { 1467 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse); 1468 if (!parseValue(properties[0], important)) 1469 return false; 1470 CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value(); 1471 addProperty(properties[1], value, important); 1472 return true; 1473 } 1474 else if (num == 2) { 1475 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse); 1476 if (!parseValue(properties[0], important) || !parseValue(properties[1], important)) 1477 return false; 1478 return true; 1479 } 1480 return false; 1481 } 1482 case CSSPropertyWebkitMarginTopCollapse: 1483 case CSSPropertyWebkitMarginBottomCollapse: 1484 if (id == CSSValueCollapse || id == CSSValueSeparate || id == CSSValueDiscard) 1485 validPrimitive = true; 1486 break; 1487 case CSSPropertyTextLineThroughMode: 1488 case CSSPropertyTextOverlineMode: 1489 case CSSPropertyTextUnderlineMode: 1490 if (id == CSSValueContinuous || id == CSSValueSkipWhiteSpace) 1491 validPrimitive = true; 1492 break; 1493 case CSSPropertyTextLineThroughStyle: 1494 case CSSPropertyTextOverlineStyle: 1495 case CSSPropertyTextUnderlineStyle: 1496 if (id == CSSValueNone || id == CSSValueSolid || id == CSSValueDouble || 1497 id == CSSValueDashed || id == CSSValueDotDash || id == CSSValueDotDotDash || 1498 id == CSSValueWave) 1499 validPrimitive = true; 1500 break; 1501 case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision 1502 if (id == CSSValueAuto || id == CSSValueOptimizespeed || id == CSSValueOptimizelegibility 1503 || id == CSSValueGeometricprecision) 1504 validPrimitive = true; 1505 break; 1506 case CSSPropertyTextLineThroughWidth: 1507 case CSSPropertyTextOverlineWidth: 1508 case CSSPropertyTextUnderlineWidth: 1509 if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin || 1510 id == CSSValueMedium || id == CSSValueThick) 1511 validPrimitive = true; 1512 else 1513 validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent, m_strict); 1514 break; 1515 case CSSPropertyResize: // none | both | horizontal | vertical | auto 1516 if (id == CSSValueNone || id == CSSValueBoth || id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto) 1517 validPrimitive = true; 1518 break; 1519 case CSSPropertyWebkitColumnCount: 1520 if (id == CSSValueAuto) 1521 validPrimitive = true; 1522 else 1523 validPrimitive = !id && validUnit(value, FInteger | FNonNeg, false); 1524 break; 1525 case CSSPropertyWebkitColumnGap: // normal | <length> 1526 if (id == CSSValueNormal) 1527 validPrimitive = true; 1528 else 1529 validPrimitive = validUnit(value, FLength | FNonNeg, m_strict); 1530 break; 1531 case CSSPropertyWebkitColumnWidth: // auto | <length> 1532 if (id == CSSValueAuto) 1533 validPrimitive = true; 1534 else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property. 1535 validPrimitive = validUnit(value, FLength, true); 1536 break; 1537 case CSSPropertyPointerEvents: 1538 // none | visiblePainted | visibleFill | visibleStroke | visible | 1539 // painted | fill | stroke | auto | all | inherit 1540 if (id == CSSValueVisible || id == CSSValueNone || id == CSSValueAll || id == CSSValueAuto || 1541 (id >= CSSValueVisiblepainted && id <= CSSValueStroke)) 1542 validPrimitive = true; 1543 break; 1544 1545 // End of CSS3 properties 1546 1547 // Apple specific properties. These will never be standardized and are purely to 1548 // support custom WebKit-based Apple applications. 1549 case CSSPropertyWebkitLineClamp: 1550 // When specifying number of lines, don't allow 0 as a valid value 1551 // When specifying either type of unit, require non-negative integers 1552 validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, false)); 1553 break; 1554 case CSSPropertyWebkitTextSizeAdjust: 1555 if (id == CSSValueAuto || id == CSSValueNone) 1556 validPrimitive = true; 1557 break; 1558 case CSSPropertyWebkitRtlOrdering: 1559 if (id == CSSValueLogical || id == CSSValueVisual) 1560 validPrimitive = true; 1561 break; 1562 1563 case CSSPropertyWebkitFontSizeDelta: // <length> 1564 validPrimitive = validUnit(value, FLength, m_strict); 1565 break; 1566 1567 case CSSPropertyWebkitNbspMode: // normal | space 1568 if (id == CSSValueNormal || id == CSSValueSpace) 1569 validPrimitive = true; 1570 break; 1571 1572 case CSSPropertyWebkitLineBreak: // normal | after-white-space 1573 if (id == CSSValueNormal || id == CSSValueAfterWhiteSpace) 1574 validPrimitive = true; 1575 break; 1576 1577 case CSSPropertyWebkitMatchNearestMailBlockquoteColor: // normal | match 1578 if (id == CSSValueNormal || id == CSSValueMatch) 1579 validPrimitive = true; 1580 break; 1581 1582 case CSSPropertyWebkitHighlight: 1583 if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING) 1584 validPrimitive = true; 1585 break; 1586 1587 case CSSPropertyWebkitBorderFit: 1588 if (id == CSSValueBorder || id == CSSValueLines) 1589 validPrimitive = true; 1590 break; 1591 1592 case CSSPropertyWebkitTextSecurity: 1593 // disc | circle | square | none | inherit 1594 if (id == CSSValueDisc || id == CSSValueCircle || id == CSSValueSquare|| id == CSSValueNone) 1595 validPrimitive = true; 1596 break; 1597 1598 case CSSPropertyWebkitFontSmoothing: 1599 if (id == CSSValueAuto || id == CSSValueNone 1600 || id == CSSValueAntialiased || id == CSSValueSubpixelAntialiased) 1601 validPrimitive = true; 1602 break; 1603 1604#if ENABLE(DASHBOARD_SUPPORT) 1605 case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region> 1606 if (value->unit == CSSParserValue::Function || id == CSSValueNone) 1607 return parseDashboardRegions(propId, important); 1608 break; 1609#endif 1610 // End Apple-specific properties 1611 1612 /* shorthand properties */ 1613 case CSSPropertyBackground: { 1614 // Position must come before color in this array because a plain old "0" is a legal color 1615 // in quirks mode but it's usually the X coordinate of a position. 1616 // FIXME: Add CSSPropertyBackgroundSize to the shorthand. 1617 const int properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat, 1618 CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin, 1619 CSSPropertyBackgroundColor }; 1620 return parseFillShorthand(propId, properties, 6, important); 1621 } 1622 case CSSPropertyWebkitMask: { 1623 const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat, 1624 CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition, 1625 CSSPropertyWebkitMaskOrigin }; 1626 return parseFillShorthand(propId, properties, 5, important); 1627 } 1628 case CSSPropertyBorder: 1629 // [ 'border-width' || 'border-style' || <color> ] | inherit 1630 { 1631 const int properties[3] = { CSSPropertyBorderWidth, CSSPropertyBorderStyle, 1632 CSSPropertyBorderColor }; 1633 return parseShorthand(propId, properties, 3, important); 1634 } 1635 case CSSPropertyBorderTop: 1636 // [ 'border-top-width' || 'border-style' || <color> ] | inherit 1637 { 1638 const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle, 1639 CSSPropertyBorderTopColor}; 1640 return parseShorthand(propId, properties, 3, important); 1641 } 1642 case CSSPropertyBorderRight: 1643 // [ 'border-right-width' || 'border-style' || <color> ] | inherit 1644 { 1645 const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle, 1646 CSSPropertyBorderRightColor }; 1647 return parseShorthand(propId, properties, 3, important); 1648 } 1649 case CSSPropertyBorderBottom: 1650 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit 1651 { 1652 const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle, 1653 CSSPropertyBorderBottomColor }; 1654 return parseShorthand(propId, properties, 3, important); 1655 } 1656 case CSSPropertyBorderLeft: 1657 // [ 'border-left-width' || 'border-style' || <color> ] | inherit 1658 { 1659 const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle, 1660 CSSPropertyBorderLeftColor }; 1661 return parseShorthand(propId, properties, 3, important); 1662 } 1663 case CSSPropertyOutline: 1664 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit 1665 { 1666 const int properties[3] = { CSSPropertyOutlineWidth, CSSPropertyOutlineStyle, 1667 CSSPropertyOutlineColor }; 1668 return parseShorthand(propId, properties, 3, important); 1669 } 1670 case CSSPropertyBorderColor: 1671 // <color>{1,4} | inherit 1672 { 1673 const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor, 1674 CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor }; 1675 return parse4Values(propId, properties, important); 1676 } 1677 case CSSPropertyBorderWidth: 1678 // <border-width>{1,4} | inherit 1679 { 1680 const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth, 1681 CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth }; 1682 return parse4Values(propId, properties, important); 1683 } 1684 case CSSPropertyBorderStyle: 1685 // <border-style>{1,4} | inherit 1686 { 1687 const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle, 1688 CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle }; 1689 return parse4Values(propId, properties, important); 1690 } 1691 case CSSPropertyMargin: 1692 // <margin-width>{1,4} | inherit 1693 { 1694 const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight, 1695 CSSPropertyMarginBottom, CSSPropertyMarginLeft }; 1696 return parse4Values(propId, properties, important); 1697 } 1698 case CSSPropertyPadding: 1699 // <padding-width>{1,4} | inherit 1700 { 1701 const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight, 1702 CSSPropertyPaddingBottom, CSSPropertyPaddingLeft }; 1703 return parse4Values(propId, properties, important); 1704 } 1705 case CSSPropertyFont: 1706 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 1707 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit 1708 if (id >= CSSValueCaption && id <= CSSValueStatusBar) 1709 validPrimitive = true; 1710 else 1711 return parseFont(important); 1712 break; 1713 case CSSPropertyListStyle: 1714 { 1715 const int properties[3] = { CSSPropertyListStyleType, CSSPropertyListStylePosition, 1716 CSSPropertyListStyleImage }; 1717 return parseShorthand(propId, properties, 3, important); 1718 } 1719 case CSSPropertyWebkitColumns: { 1720 const int properties[2] = { CSSPropertyWebkitColumnWidth, CSSPropertyWebkitColumnCount }; 1721 return parseShorthand(propId, properties, 2, important); 1722 } 1723 case CSSPropertyWebkitColumnRule: { 1724 const int properties[3] = { CSSPropertyWebkitColumnRuleWidth, CSSPropertyWebkitColumnRuleStyle, 1725 CSSPropertyWebkitColumnRuleColor }; 1726 return parseShorthand(propId, properties, 3, important); 1727 } 1728 case CSSPropertyWebkitTextStroke: { 1729 const int properties[2] = { CSSPropertyWebkitTextStrokeWidth, CSSPropertyWebkitTextStrokeColor }; 1730 return parseShorthand(propId, properties, 2, important); 1731 } 1732 case CSSPropertyWebkitAnimation: 1733 return parseAnimationShorthand(important); 1734 case CSSPropertyWebkitTransition: 1735 return parseTransitionShorthand(important); 1736 case CSSPropertyInvalid: 1737 return false; 1738 case CSSPropertyFontStretch: 1739 case CSSPropertyPage: 1740 case CSSPropertyTextLineThrough: 1741 case CSSPropertyTextOverline: 1742 case CSSPropertyTextUnderline: 1743 case CSSPropertyWebkitVariableDeclarationBlock: 1744 return false; 1745#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR 1746 case CSSPropertyWebkitTapHighlightColor: 1747 parsedValue = parseColor(); 1748 if (parsedValue) 1749 m_valueList->next(); 1750 break; 1751#endif 1752 1753#if ENABLE(SVG) 1754 default: 1755 return parseSVGValue(propId, important); 1756#endif 1757 } 1758 1759 if (validPrimitive) { 1760 if (id != 0) 1761 parsedValue = CSSPrimitiveValue::createIdentifier(id); 1762 else if (value->unit == CSSPrimitiveValue::CSS_STRING) 1763 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit); 1764 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) 1765 parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); 1766 else if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS) 1767 parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); 1768 else if (value->unit >= CSSParserValue::Q_EMS) 1769 parsedValue = CSSQuirkPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_EMS); 1770 m_valueList->next(); 1771 } 1772 if (parsedValue) { 1773 if (!m_valueList->current() || inShorthand()) { 1774 addProperty(propId, parsedValue.release(), important); 1775 return true; 1776 } 1777 } 1778 return false; 1779} 1780 1781void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval) 1782{ 1783 if (lval) { 1784 if (lval->isValueList()) 1785 static_cast<CSSValueList*>(lval.get())->append(rval); 1786 else { 1787 PassRefPtr<CSSValue> oldlVal(lval.release()); 1788 PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); 1789 list->append(oldlVal); 1790 list->append(rval); 1791 lval = list; 1792 } 1793 } 1794 else 1795 lval = rval; 1796} 1797 1798static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue) 1799{ 1800 if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox || parserValue->id == CSSValueWebkitText) { 1801 cssValue = CSSPrimitiveValue::createIdentifier(parserValue->id); 1802 return true; 1803 } 1804 return false; 1805} 1806 1807const int cMaxFillProperties = 9; 1808 1809bool CSSParser::parseFillShorthand(int propId, const int* properties, int numProperties, bool important) 1810{ 1811 ASSERT(numProperties <= cMaxFillProperties); 1812 if (numProperties > cMaxFillProperties) 1813 return false; 1814 1815 ShorthandScope scope(this, propId); 1816 1817 bool parsedProperty[cMaxFillProperties] = { false }; 1818 RefPtr<CSSValue> values[cMaxFillProperties]; 1819 RefPtr<CSSValue> clipValue; 1820 RefPtr<CSSValue> positionYValue; 1821 RefPtr<CSSValue> repeatYValue; 1822 int i; 1823 1824 while (m_valueList->current()) { 1825 CSSParserValue* val = m_valueList->current(); 1826 if (val->unit == CSSParserValue::Operator && val->iValue == ',') { 1827 // We hit the end. Fill in all remaining values with the initial value. 1828 m_valueList->next(); 1829 for (i = 0; i < numProperties; ++i) { 1830 if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i]) 1831 // Color is not allowed except as the last item in a list for backgrounds. 1832 // Reject the entire property. 1833 return false; 1834 1835 if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) { 1836 addFillValue(values[i], CSSInitialValue::createImplicit()); 1837 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) 1838 addFillValue(positionYValue, CSSInitialValue::createImplicit()); 1839 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) 1840 addFillValue(repeatYValue, CSSInitialValue::createImplicit()); 1841 if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) { 1842 // If background-origin wasn't present, then reset background-clip also. 1843 addFillValue(clipValue, CSSInitialValue::createImplicit()); 1844 } 1845 } 1846 parsedProperty[i] = false; 1847 } 1848 if (!m_valueList->current()) 1849 break; 1850 } 1851 1852 bool found = false; 1853 for (i = 0; !found && i < numProperties; ++i) { 1854 if (!parsedProperty[i]) { 1855 RefPtr<CSSValue> val1; 1856 RefPtr<CSSValue> val2; 1857 int propId1, propId2; 1858 CSSParserValue* parserValue = m_valueList->current(); 1859 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) { 1860 parsedProperty[i] = found = true; 1861 addFillValue(values[i], val1.release()); 1862 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) 1863 addFillValue(positionYValue, val2.release()); 1864 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) 1865 addFillValue(repeatYValue, val2.release()); 1866 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) { 1867 // Reparse the value as a clip, and see if we succeed. 1868 if (parseBackgroundClip(parserValue, val1)) 1869 addFillValue(clipValue, val1.release()); // The property parsed successfully. 1870 else 1871 addFillValue(clipValue, CSSInitialValue::createImplicit()); // Some value was used for origin that is not supported by clip. Just reset clip instead. 1872 } 1873 } 1874 } 1875 } 1876 1877 // if we didn't find at least one match, this is an 1878 // invalid shorthand and we have to ignore it 1879 if (!found) 1880 return false; 1881 } 1882 1883 // Fill in any remaining properties with the initial value. 1884 for (i = 0; i < numProperties; ++i) { 1885 if (!parsedProperty[i]) { 1886 addFillValue(values[i], CSSInitialValue::createImplicit()); 1887 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) 1888 addFillValue(positionYValue, CSSInitialValue::createImplicit()); 1889 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) 1890 addFillValue(repeatYValue, CSSInitialValue::createImplicit()); 1891 if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) { 1892 // If background-origin wasn't present, then reset background-clip also. 1893 addFillValue(clipValue, CSSInitialValue::createImplicit()); 1894 } 1895 } 1896 } 1897 1898 // Now add all of the properties we found. 1899 for (i = 0; i < numProperties; i++) { 1900 if (properties[i] == CSSPropertyBackgroundPosition) { 1901 addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important); 1902 // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once 1903 addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important); 1904 } else if (properties[i] == CSSPropertyWebkitMaskPosition) { 1905 addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important); 1906 // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once 1907 addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important); 1908 } else if (properties[i] == CSSPropertyBackgroundRepeat) { 1909 addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important); 1910 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once 1911 addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important); 1912 } else if (properties[i] == CSSPropertyWebkitMaskRepeat) { 1913 addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important); 1914 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once 1915 addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important); 1916 } else 1917 addProperty(properties[i], values[i].release(), important); 1918 1919 // Add in clip values when we hit the corresponding origin property. 1920 if (properties[i] == CSSPropertyBackgroundOrigin) 1921 addProperty(CSSPropertyBackgroundClip, clipValue.release(), important); 1922 else if (properties[i] == CSSPropertyWebkitMaskOrigin) 1923 addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important); 1924 } 1925 1926 return true; 1927} 1928 1929void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval) 1930{ 1931 if (lval) { 1932 if (lval->isValueList()) 1933 static_cast<CSSValueList*>(lval.get())->append(rval); 1934 else { 1935 PassRefPtr<CSSValue> oldVal(lval.release()); 1936 PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); 1937 list->append(oldVal); 1938 list->append(rval); 1939 lval = list; 1940 } 1941 } 1942 else 1943 lval = rval; 1944} 1945 1946bool CSSParser::parseAnimationShorthand(bool important) 1947{ 1948 const int properties[] = { CSSPropertyWebkitAnimationName, 1949 CSSPropertyWebkitAnimationDuration, 1950 CSSPropertyWebkitAnimationTimingFunction, 1951 CSSPropertyWebkitAnimationDelay, 1952 CSSPropertyWebkitAnimationIterationCount, 1953 CSSPropertyWebkitAnimationDirection }; 1954 const int numProperties = sizeof(properties) / sizeof(properties[0]); 1955 1956 ShorthandScope scope(this, CSSPropertyWebkitAnimation); 1957 1958 bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary 1959 RefPtr<CSSValue> values[numProperties]; 1960 1961 int i; 1962 while (m_valueList->current()) { 1963 CSSParserValue* val = m_valueList->current(); 1964 if (val->unit == CSSParserValue::Operator && val->iValue == ',') { 1965 // We hit the end. Fill in all remaining values with the initial value. 1966 m_valueList->next(); 1967 for (i = 0; i < numProperties; ++i) { 1968 if (!parsedProperty[i]) 1969 addAnimationValue(values[i], CSSInitialValue::createImplicit()); 1970 parsedProperty[i] = false; 1971 } 1972 if (!m_valueList->current()) 1973 break; 1974 } 1975 1976 bool found = false; 1977 for (i = 0; !found && i < numProperties; ++i) { 1978 if (!parsedProperty[i]) { 1979 RefPtr<CSSValue> val; 1980 if (parseAnimationProperty(properties[i], val)) { 1981 parsedProperty[i] = found = true; 1982 addAnimationValue(values[i], val.release()); 1983 } 1984 } 1985 } 1986 1987 // if we didn't find at least one match, this is an 1988 // invalid shorthand and we have to ignore it 1989 if (!found) 1990 return false; 1991 } 1992 1993 // Fill in any remaining properties with the initial value. 1994 for (i = 0; i < numProperties; ++i) { 1995 if (!parsedProperty[i]) 1996 addAnimationValue(values[i], CSSInitialValue::createImplicit()); 1997 } 1998 1999 // Now add all of the properties we found. 2000 for (i = 0; i < numProperties; i++) 2001 addProperty(properties[i], values[i].release(), important); 2002 2003 return true; 2004} 2005 2006bool CSSParser::parseTransitionShorthand(bool important) 2007{ 2008 const int properties[] = { CSSPropertyWebkitTransitionProperty, 2009 CSSPropertyWebkitTransitionDuration, 2010 CSSPropertyWebkitTransitionTimingFunction, 2011 CSSPropertyWebkitTransitionDelay }; 2012 const int numProperties = sizeof(properties) / sizeof(properties[0]); 2013 2014 ShorthandScope scope(this, CSSPropertyWebkitTransition); 2015 2016 bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary 2017 RefPtr<CSSValue> values[numProperties]; 2018 2019 int i; 2020 while (m_valueList->current()) { 2021 CSSParserValue* val = m_valueList->current(); 2022 if (val->unit == CSSParserValue::Operator && val->iValue == ',') { 2023 // We hit the end. Fill in all remaining values with the initial value. 2024 m_valueList->next(); 2025 for (i = 0; i < numProperties; ++i) { 2026 if (!parsedProperty[i]) 2027 addAnimationValue(values[i], CSSInitialValue::createImplicit()); 2028 parsedProperty[i] = false; 2029 } 2030 if (!m_valueList->current()) 2031 break; 2032 } 2033 2034 bool found = false; 2035 for (i = 0; !found && i < numProperties; ++i) { 2036 if (!parsedProperty[i]) { 2037 RefPtr<CSSValue> val; 2038 if (parseAnimationProperty(properties[i], val)) { 2039 parsedProperty[i] = found = true; 2040 addAnimationValue(values[i], val.release()); 2041 } 2042 } 2043 } 2044 2045 // if we didn't find at least one match, this is an 2046 // invalid shorthand and we have to ignore it 2047 if (!found) 2048 return false; 2049 } 2050 2051 // Fill in any remaining properties with the initial value. 2052 for (i = 0; i < numProperties; ++i) { 2053 if (!parsedProperty[i]) 2054 addAnimationValue(values[i], CSSInitialValue::createImplicit()); 2055 } 2056 2057 // Now add all of the properties we found. 2058 for (i = 0; i < numProperties; i++) 2059 addProperty(properties[i], values[i].release(), important); 2060 2061 return true; 2062} 2063 2064bool CSSParser::parseShorthand(int propId, const int *properties, int numProperties, bool important) 2065{ 2066 // We try to match as many properties as possible 2067 // We set up an array of booleans to mark which property has been found, 2068 // and we try to search for properties until it makes no longer any sense. 2069 ShorthandScope scope(this, propId); 2070 2071 bool found = false; 2072 bool fnd[6]; // Trust me ;) 2073 for (int i = 0; i < numProperties; i++) 2074 fnd[i] = false; 2075 2076 while (m_valueList->current()) { 2077 found = false; 2078 for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) { 2079 if (!fnd[propIndex]) { 2080 if (parseValue(properties[propIndex], important)) 2081 fnd[propIndex] = found = true; 2082 } 2083 } 2084 2085 // if we didn't find at least one match, this is an 2086 // invalid shorthand and we have to ignore it 2087 if (!found) 2088 return false; 2089 } 2090 2091 // Fill in any remaining properties with the initial value. 2092 m_implicitShorthand = true; 2093 for (int i = 0; i < numProperties; ++i) { 2094 if (!fnd[i]) 2095 addProperty(properties[i], CSSInitialValue::createImplicit(), important); 2096 } 2097 m_implicitShorthand = false; 2098 2099 return true; 2100} 2101 2102bool CSSParser::parse4Values(int propId, const int *properties, bool important) 2103{ 2104 /* From the CSS 2 specs, 8.3 2105 * If there is only one value, it applies to all sides. If there are two values, the top and 2106 * bottom margins are set to the first value and the right and left margins are set to the second. 2107 * If there are three values, the top is set to the first value, the left and right are set to the 2108 * second, and the bottom is set to the third. If there are four values, they apply to the top, 2109 * right, bottom, and left, respectively. 2110 */ 2111 2112 int num = inShorthand() ? 1 : m_valueList->size(); 2113 2114 ShorthandScope scope(this, propId); 2115 2116 // the order is top, right, bottom, left 2117 switch (num) { 2118 case 1: { 2119 if (!parseValue(properties[0], important)) 2120 return false; 2121 CSSValue *value = m_parsedProperties[m_numParsedProperties-1]->value(); 2122 m_implicitShorthand = true; 2123 addProperty(properties[1], value, important); 2124 addProperty(properties[2], value, important); 2125 addProperty(properties[3], value, important); 2126 m_implicitShorthand = false; 2127 break; 2128 } 2129 case 2: { 2130 if (!parseValue(properties[0], important) || !parseValue(properties[1], important)) 2131 return false; 2132 CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value(); 2133 m_implicitShorthand = true; 2134 addProperty(properties[2], value, important); 2135 value = m_parsedProperties[m_numParsedProperties-2]->value(); 2136 addProperty(properties[3], value, important); 2137 m_implicitShorthand = false; 2138 break; 2139 } 2140 case 3: { 2141 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important)) 2142 return false; 2143 CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value(); 2144 m_implicitShorthand = true; 2145 addProperty(properties[3], value, important); 2146 m_implicitShorthand = false; 2147 break; 2148 } 2149 case 4: { 2150 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || 2151 !parseValue(properties[2], important) || !parseValue(properties[3], important)) 2152 return false; 2153 break; 2154 } 2155 default: { 2156 return false; 2157 } 2158 } 2159 2160 return true; 2161} 2162 2163// [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit 2164// in CSS 2.1 this got somewhat reduced: 2165// [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit 2166bool CSSParser::parseContent(int propId, bool important) 2167{ 2168 RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated(); 2169 2170 while (CSSParserValue* val = m_valueList->current()) { 2171 RefPtr<CSSValue> parsedValue; 2172 if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) { 2173 // url 2174 // FIXME: The completeURL call should be done when using the CSSImageValue, 2175 // not when creating it. 2176 parsedValue = CSSImageValue::create(m_styleSheet->completeURL(val->string)); 2177 } else if (val->unit == CSSParserValue::Function) { 2178 // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...) 2179 CSSParserValueList* args = val->function->args; 2180 if (!args) 2181 return false; 2182 if (equalIgnoringCase(val->function->name, "attr(")) { 2183 parsedValue = parseAttr(args); 2184 if (!parsedValue) 2185 return false; 2186 } else if (equalIgnoringCase(val->function->name, "counter(")) { 2187 parsedValue = parseCounterContent(args, false); 2188 if (!parsedValue) 2189 return false; 2190 } else if (equalIgnoringCase(val->function->name, "counters(")) { 2191 parsedValue = parseCounterContent(args, true); 2192 if (!parsedValue) 2193 return false; 2194 } else if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) { 2195 if (!parseGradient(parsedValue)) 2196 return false; 2197 } else if (equalIgnoringCase(val->function->name, "-webkit-canvas(")) { 2198 if (!parseCanvas(parsedValue)) 2199 return false; 2200 } else 2201 return false; 2202 } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) { 2203 // open-quote 2204 // close-quote 2205 // no-open-quote 2206 // no-close-quote 2207 // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503). 2208 } else if (val->unit == CSSPrimitiveValue::CSS_STRING) { 2209 parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING); 2210 } 2211 if (!parsedValue) 2212 break; 2213 values->append(parsedValue.release()); 2214 m_valueList->next(); 2215 } 2216 2217 if (values->length()) { 2218 addProperty(propId, values.release(), important); 2219 m_valueList->next(); 2220 return true; 2221 } 2222 2223 return false; 2224} 2225 2226PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args) 2227{ 2228 if (args->size() != 1) 2229 return 0; 2230 2231 CSSParserValue* a = args->current(); 2232 2233 if (a->unit != CSSPrimitiveValue::CSS_IDENT) 2234 return 0; 2235 2236 String attrName = a->string; 2237 // CSS allows identifiers with "-" at the start, like "-webkit-mask-image". 2238 // But HTML attribute names can't have those characters, and we should not 2239 // even parse them inside attr(). 2240 if (attrName[0] == '-') 2241 return 0; 2242 2243 if (document() && document()->isHTMLDocument()) 2244 attrName = attrName.lower(); 2245 2246 return CSSPrimitiveValue::create(attrName, CSSPrimitiveValue::CSS_ATTR); 2247} 2248 2249PassRefPtr<CSSValue> CSSParser::parseBackgroundColor() 2250{ 2251 int id = m_valueList->current()->id; 2252 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor || 2253 (id >= CSSValueGrey && id < CSSValueWebkitText && !m_strict)) 2254 return CSSPrimitiveValue::createIdentifier(id); 2255 return parseColor(); 2256} 2257 2258bool CSSParser::parseFillImage(RefPtr<CSSValue>& value) 2259{ 2260 if (m_valueList->current()->id == CSSValueNone) { 2261 value = CSSImageValue::create(); 2262 return true; 2263 } 2264 if (m_valueList->current()->unit == CSSPrimitiveValue::CSS_URI) { 2265 // FIXME: The completeURL call should be done when using the CSSImageValue, 2266 // not when creating it. 2267 if (m_styleSheet) 2268 value = CSSImageValue::create(m_styleSheet->completeURL(m_valueList->current()->string)); 2269 return true; 2270 } 2271 2272 if (m_valueList->current()->unit == CSSParserValue::Function) { 2273 if (equalIgnoringCase(m_valueList->current()->function->name, "-webkit-gradient(")) 2274 return parseGradient(value); 2275 if (equalIgnoringCase(m_valueList->current()->function->name, "-webkit-canvas(")) 2276 return parseCanvas(value); 2277 } 2278 2279 return false; 2280} 2281 2282PassRefPtr<CSSValue> CSSParser::parseFillPositionXY(bool& xFound, bool& yFound) 2283{ 2284 int id = m_valueList->current()->id; 2285 if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) { 2286 int percent = 0; 2287 if (id == CSSValueLeft || id == CSSValueRight) { 2288 if (xFound) 2289 return 0; 2290 xFound = true; 2291 if (id == CSSValueRight) 2292 percent = 100; 2293 } 2294 else if (id == CSSValueTop || id == CSSValueBottom) { 2295 if (yFound) 2296 return 0; 2297 yFound = true; 2298 if (id == CSSValueBottom) 2299 percent = 100; 2300 } 2301 else if (id == CSSValueCenter) 2302 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y. 2303 percent = 50; 2304 return CSSPrimitiveValue::create(percent, CSSPrimitiveValue::CSS_PERCENTAGE); 2305 } 2306 if (validUnit(m_valueList->current(), FPercent | FLength, m_strict)) 2307 return CSSPrimitiveValue::create(m_valueList->current()->fValue, 2308 (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit); 2309 2310 return 0; 2311} 2312 2313void CSSParser::parseFillPosition(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2) 2314{ 2315 CSSParserValue* value = m_valueList->current(); 2316 2317 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length. 2318 bool value1IsX = false, value1IsY = false; 2319 value1 = parseFillPositionXY(value1IsX, value1IsY); 2320 if (!value1) 2321 return; 2322 2323 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we 2324 // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the 2325 // value was explicitly specified for our property. 2326 value = m_valueList->next(); 2327 2328 // First check for the comma. If so, we are finished parsing this value or value pair. 2329 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',') 2330 value = 0; 2331 2332 bool value2IsX = false, value2IsY = false; 2333 if (value) { 2334 value2 = parseFillPositionXY(value2IsX, value2IsY); 2335 if (value2) 2336 m_valueList->next(); 2337 else { 2338 if (!inShorthand()) { 2339 value1.clear(); 2340 return; 2341 } 2342 } 2343 } 2344 2345 if (!value2) 2346 // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position 2347 // is simply 50%. This is our default. 2348 // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center). 2349 // For left/right/center, the default of 50% in the y is still correct. 2350 value2 = CSSPrimitiveValue::create(50, CSSPrimitiveValue::CSS_PERCENTAGE); 2351 2352 if (value1IsY || value2IsX) 2353 value1.swap(value2); 2354} 2355 2356void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2) 2357{ 2358 CSSParserValue* value = m_valueList->current(); 2359 2360 int id = m_valueList->current()->id; 2361 if (id == CSSValueRepeatX) { 2362 m_implicitShorthand = true; 2363 value1 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat); 2364 value2 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat); 2365 m_valueList->next(); 2366 return; 2367 } 2368 if (id == CSSValueRepeatY) { 2369 m_implicitShorthand = true; 2370 value1 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat); 2371 value2 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat); 2372 m_valueList->next(); 2373 return; 2374 } 2375 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) 2376 value1 = CSSPrimitiveValue::createIdentifier(id); 2377 else { 2378 value1 = 0; 2379 return; 2380 } 2381 2382 value = m_valueList->next(); 2383 2384 // First check for the comma. If so, we are finished parsing this value or value pair. 2385 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',') 2386 value = 0; 2387 2388 if (value) 2389 id = m_valueList->current()->id; 2390 2391 if (value && (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)) { 2392 value2 = CSSPrimitiveValue::createIdentifier(id); 2393 m_valueList->next(); 2394 } else { 2395 // If only one value was specified, value2 is the same as value1. 2396 m_implicitShorthand = true; 2397 value2 = CSSPrimitiveValue::createIdentifier(static_cast<CSSPrimitiveValue*>(value1.get())->getIdent()); 2398 } 2399} 2400 2401PassRefPtr<CSSValue> CSSParser::parseFillSize(int propId, bool& allowComma) 2402{ 2403 allowComma = true; 2404 CSSParserValue* value = m_valueList->current(); 2405 2406 if (value->id == CSSValueContain || value->id == CSSValueCover) 2407 return CSSPrimitiveValue::createIdentifier(value->id); 2408 2409 RefPtr<CSSPrimitiveValue> parsedValue1; 2410 2411 if (value->id == CSSValueAuto) 2412 parsedValue1 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN); 2413 else { 2414 if (!validUnit(value, FLength | FPercent, m_strict)) 2415 return 0; 2416 parsedValue1 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); 2417 } 2418 2419 CSSPropertyID property = static_cast<CSSPropertyID>(propId); 2420 RefPtr<CSSPrimitiveValue> parsedValue2; 2421 if ((value = m_valueList->next())) { 2422 if (value->id == CSSValueAuto) 2423 parsedValue2 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN); 2424 else if (value->unit == CSSParserValue::Operator && value->iValue == ',') 2425 allowComma = false; 2426 else { 2427 if (!validUnit(value, FLength | FPercent, m_strict)) 2428 return 0; 2429 parsedValue2 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); 2430 } 2431 } 2432 if (!parsedValue2) { 2433 if (property == CSSPropertyWebkitBackgroundSize || property == CSSPropertyWebkitMaskSize) 2434 parsedValue2 = parsedValue1; 2435 else 2436 parsedValue2 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN); 2437 } 2438 2439 return CSSPrimitiveValue::create(Pair::create(parsedValue1.release(), parsedValue2.release())); 2440} 2441 2442bool CSSParser::parseFillProperty(int propId, int& propId1, int& propId2, 2443 RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2) 2444{ 2445 RefPtr<CSSValueList> values; 2446 RefPtr<CSSValueList> values2; 2447 CSSParserValue* val; 2448 RefPtr<CSSValue> value; 2449 RefPtr<CSSValue> value2; 2450 2451 bool allowComma = false; 2452 2453 retValue1 = retValue2 = 0; 2454 propId1 = propId; 2455 propId2 = propId; 2456 if (propId == CSSPropertyBackgroundPosition) { 2457 propId1 = CSSPropertyBackgroundPositionX; 2458 propId2 = CSSPropertyBackgroundPositionY; 2459 } else if (propId == CSSPropertyWebkitMaskPosition) { 2460 propId1 = CSSPropertyWebkitMaskPositionX; 2461 propId2 = CSSPropertyWebkitMaskPositionY; 2462 } else if (propId == CSSPropertyBackgroundRepeat) { 2463 propId1 = CSSPropertyBackgroundRepeatX; 2464 propId2 = CSSPropertyBackgroundRepeatY; 2465 } else if (propId == CSSPropertyWebkitMaskRepeat) { 2466 propId1 = CSSPropertyWebkitMaskRepeatX; 2467 propId2 = CSSPropertyWebkitMaskRepeatY; 2468 } 2469 2470 while ((val = m_valueList->current())) { 2471 RefPtr<CSSValue> currValue; 2472 RefPtr<CSSValue> currValue2; 2473 2474 if (allowComma) { 2475 if (val->unit != CSSParserValue::Operator || val->iValue != ',') 2476 return false; 2477 m_valueList->next(); 2478 allowComma = false; 2479 } else { 2480 allowComma = true; 2481 switch (propId) { 2482 case CSSPropertyBackgroundColor: 2483 currValue = parseBackgroundColor(); 2484 if (currValue) 2485 m_valueList->next(); 2486 break; 2487 case CSSPropertyBackgroundAttachment: 2488 case CSSPropertyWebkitMaskAttachment: 2489 if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) { 2490 currValue = CSSPrimitiveValue::createIdentifier(val->id); 2491 m_valueList->next(); 2492 } 2493 break; 2494 case CSSPropertyBackgroundImage: 2495 case CSSPropertyWebkitMaskImage: 2496 if (parseFillImage(currValue)) 2497 m_valueList->next(); 2498 break; 2499 case CSSPropertyWebkitBackgroundClip: 2500 case CSSPropertyWebkitBackgroundOrigin: 2501 case CSSPropertyWebkitMaskClip: 2502 case CSSPropertyWebkitMaskOrigin: 2503 // The first three values here are deprecated and do not apply to the version of the property that has 2504 // the -webkit- prefix removed. 2505 if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent || 2506 val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox || 2507 ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) && 2508 (val->id == CSSValueText || val->id == CSSValueWebkitText))) { 2509 currValue = CSSPrimitiveValue::createIdentifier(val->id); 2510 m_valueList->next(); 2511 } 2512 break; 2513 case CSSPropertyBackgroundClip: 2514 if (parseBackgroundClip(val, currValue)) 2515 m_valueList->next(); 2516 break; 2517 case CSSPropertyBackgroundOrigin: 2518 if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) { 2519 currValue = CSSPrimitiveValue::createIdentifier(val->id); 2520 m_valueList->next(); 2521 } 2522 break; 2523 case CSSPropertyBackgroundPosition: 2524 case CSSPropertyWebkitMaskPosition: 2525 parseFillPosition(currValue, currValue2); 2526 // parseFillPosition advances the m_valueList pointer 2527 break; 2528 case CSSPropertyBackgroundPositionX: 2529 case CSSPropertyWebkitMaskPositionX: { 2530 bool xFound = false, yFound = true; 2531 currValue = parseFillPositionXY(xFound, yFound); 2532 if (currValue) 2533 m_valueList->next(); 2534 break; 2535 } 2536 case CSSPropertyBackgroundPositionY: 2537 case CSSPropertyWebkitMaskPositionY: { 2538 bool xFound = true, yFound = false; 2539 currValue = parseFillPositionXY(xFound, yFound); 2540 if (currValue) 2541 m_valueList->next(); 2542 break; 2543 } 2544 case CSSPropertyWebkitBackgroundComposite: 2545 case CSSPropertyWebkitMaskComposite: 2546 if ((val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) || val->id == CSSValueHighlight) { 2547 currValue = CSSPrimitiveValue::createIdentifier(val->id); 2548 m_valueList->next(); 2549 } 2550 break; 2551 case CSSPropertyBackgroundRepeat: 2552 case CSSPropertyWebkitMaskRepeat: 2553 parseFillRepeat(currValue, currValue2); 2554 // parseFillRepeat advances the m_valueList pointer 2555 break; 2556 case CSSPropertyBackgroundSize: 2557 case CSSPropertyWebkitBackgroundSize: 2558 case CSSPropertyWebkitMaskSize: { 2559 currValue = parseFillSize(propId, allowComma); 2560 if (currValue) 2561 m_valueList->next(); 2562 break; 2563 } 2564 } 2565 if (!currValue) 2566 return false; 2567 2568 if (value && !values) { 2569 values = CSSValueList::createCommaSeparated(); 2570 values->append(value.release()); 2571 } 2572 2573 if (value2 && !values2) { 2574 values2 = CSSValueList::createCommaSeparated(); 2575 values2->append(value2.release()); 2576 } 2577 2578 if (values) 2579 values->append(currValue.release()); 2580 else 2581 value = currValue.release(); 2582 if (currValue2) { 2583 if (values2) 2584 values2->append(currValue2.release()); 2585 else 2586 value2 = currValue2.release(); 2587 } 2588 } 2589 2590 // When parsing any fill shorthand property, we let it handle building up the lists for all 2591 // properties. 2592 if (inShorthand()) 2593 break; 2594 } 2595 2596 if (values && values->length()) { 2597 retValue1 = values.release(); 2598 if (values2 && values2->length()) 2599 retValue2 = values2.release(); 2600 return true; 2601 } 2602 if (value) { 2603 retValue1 = value.release(); 2604 retValue2 = value2.release(); 2605 return true; 2606 } 2607 return false; 2608} 2609 2610PassRefPtr<CSSValue> CSSParser::parseAnimationDelay() 2611{ 2612 CSSParserValue* value = m_valueList->current(); 2613 if (validUnit(value, FTime, m_strict)) 2614 return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); 2615 return 0; 2616} 2617 2618PassRefPtr<CSSValue> CSSParser::parseAnimationDirection() 2619{ 2620 CSSParserValue* value = m_valueList->current(); 2621 if (value->id == CSSValueNormal || value->id == CSSValueAlternate) 2622 return CSSPrimitiveValue::createIdentifier(value->id); 2623 return 0; 2624} 2625 2626PassRefPtr<CSSValue> CSSParser::parseAnimationDuration() 2627{ 2628 CSSParserValue* value = m_valueList->current(); 2629 if (validUnit(value, FTime | FNonNeg, m_strict)) 2630 return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); 2631 return 0; 2632} 2633 2634PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount() 2635{ 2636 CSSParserValue* value = m_valueList->current(); 2637 if (value->id == CSSValueInfinite) 2638 return CSSPrimitiveValue::createIdentifier(value->id); 2639 if (validUnit(value, FInteger | FNonNeg, m_strict)) 2640 return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); 2641 return 0; 2642} 2643 2644PassRefPtr<CSSValue> CSSParser::parseAnimationName() 2645{ 2646 CSSParserValue* value = m_valueList->current(); 2647 if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) { 2648 if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value->string, "none"))) { 2649 return CSSPrimitiveValue::createIdentifier(CSSValueNone); 2650 } else { 2651 return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_STRING); 2652 } 2653 } 2654 return 0; 2655} 2656 2657PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState() 2658{ 2659 CSSParserValue* value = m_valueList->current(); 2660 if (value->id == CSSValueRunning || value->id == CSSValuePaused) 2661 return CSSPrimitiveValue::createIdentifier(value->id); 2662 return 0; 2663} 2664 2665PassRefPtr<CSSValue> CSSParser::parseAnimationProperty() 2666{ 2667 CSSParserValue* value = m_valueList->current(); 2668 if (value->unit != CSSPrimitiveValue::CSS_IDENT) 2669 return 0; 2670 int result = cssPropertyID(value->string); 2671 if (result) 2672 return CSSPrimitiveValue::createIdentifier(result); 2673 if (equalIgnoringCase(value->string, "all")) 2674 return CSSPrimitiveValue::createIdentifier(CSSValueAll); 2675 if (equalIgnoringCase(value->string, "none")) 2676 return CSSPrimitiveValue::createIdentifier(CSSValueNone); 2677 return 0; 2678} 2679 2680void CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3) 2681{ 2682 parseFillPosition(value1, value2); 2683 2684 // now get z 2685 if (m_valueList->current() && validUnit(m_valueList->current(), FLength, m_strict)) 2686 value3 = CSSPrimitiveValue::create(m_valueList->current()->fValue, 2687 (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit); 2688 if (value3) 2689 m_valueList->next(); 2690} 2691 2692bool CSSParser::parseTimingFunctionValue(CSSParserValueList*& args, double& result) 2693{ 2694 CSSParserValue* v = args->current(); 2695 if (!validUnit(v, FNumber, m_strict)) 2696 return false; 2697 result = v->fValue; 2698 if (result < 0 || result > 1.0) 2699 return false; 2700 v = args->next(); 2701 if (!v) 2702 // The last number in the function has no comma after it, so we're done. 2703 return true; 2704 if (v->unit != CSSParserValue::Operator && v->iValue != ',') 2705 return false; 2706 v = args->next(); 2707 return true; 2708} 2709 2710PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction() 2711{ 2712 CSSParserValue* value = m_valueList->current(); 2713 if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut || value->id == CSSValueEaseInOut) 2714 return CSSPrimitiveValue::createIdentifier(value->id); 2715 2716 // We must be a function. 2717 if (value->unit != CSSParserValue::Function) 2718 return 0; 2719 2720 // The only timing function we accept for now is a cubic bezier function. 4 points must be specified. 2721 CSSParserValueList* args = value->function->args; 2722 if (!equalIgnoringCase(value->function->name, "cubic-bezier(") || !args || args->size() != 7) 2723 return 0; 2724 2725 // There are two points specified. The values must be between 0 and 1. 2726 double x1, y1, x2, y2; 2727 2728 if (!parseTimingFunctionValue(args, x1)) 2729 return 0; 2730 if (!parseTimingFunctionValue(args, y1)) 2731 return 0; 2732 if (!parseTimingFunctionValue(args, x2)) 2733 return 0; 2734 if (!parseTimingFunctionValue(args, y2)) 2735 return 0; 2736 2737 return CSSTimingFunctionValue::create(x1, y1, x2, y2); 2738} 2739 2740bool CSSParser::parseAnimationProperty(int propId, RefPtr<CSSValue>& result) 2741{ 2742 RefPtr<CSSValueList> values; 2743 CSSParserValue* val; 2744 RefPtr<CSSValue> value; 2745 bool allowComma = false; 2746 2747 result = 0; 2748 2749 while ((val = m_valueList->current())) { 2750 RefPtr<CSSValue> currValue; 2751 if (allowComma) { 2752 if (val->unit != CSSParserValue::Operator || val->iValue != ',') 2753 return false; 2754 m_valueList->next(); 2755 allowComma = false; 2756 } 2757 else { 2758 switch (propId) { 2759 case CSSPropertyWebkitAnimationDelay: 2760 case CSSPropertyWebkitTransitionDelay: 2761 currValue = parseAnimationDelay(); 2762 if (currValue) 2763 m_valueList->next(); 2764 break; 2765 case CSSPropertyWebkitAnimationDirection: 2766 currValue = parseAnimationDirection(); 2767 if (currValue) 2768 m_valueList->next(); 2769 break; 2770 case CSSPropertyWebkitAnimationDuration: 2771 case CSSPropertyWebkitTransitionDuration: 2772 currValue = parseAnimationDuration(); 2773 if (currValue) 2774 m_valueList->next(); 2775 break; 2776 case CSSPropertyWebkitAnimationIterationCount: 2777 currValue = parseAnimationIterationCount(); 2778 if (currValue) 2779 m_valueList->next(); 2780 break; 2781 case CSSPropertyWebkitAnimationName: 2782 currValue = parseAnimationName(); 2783 if (currValue) 2784 m_valueList->next(); 2785 break; 2786 case CSSPropertyWebkitAnimationPlayState: 2787 currValue = parseAnimationPlayState(); 2788 if (currValue) 2789 m_valueList->next(); 2790 break; 2791 case CSSPropertyWebkitTransitionProperty: 2792 currValue = parseAnimationProperty(); 2793 if (currValue) 2794 m_valueList->next(); 2795 break; 2796 case CSSPropertyWebkitAnimationTimingFunction: 2797 case CSSPropertyWebkitTransitionTimingFunction: 2798 currValue = parseAnimationTimingFunction(); 2799 if (currValue) 2800 m_valueList->next(); 2801 break; 2802 } 2803 2804 if (!currValue) 2805 return false; 2806 2807 if (value && !values) { 2808 values = CSSValueList::createCommaSeparated(); 2809 values->append(value.release()); 2810 } 2811 2812 if (values) 2813 values->append(currValue.release()); 2814 else 2815 value = currValue.release(); 2816 2817 allowComma = true; 2818 } 2819 2820 // When parsing the 'transition' shorthand property, we let it handle building up the lists for all 2821 // properties. 2822 if (inShorthand()) 2823 break; 2824 } 2825 2826 if (values && values->length()) { 2827 result = values.release(); 2828 return true; 2829 } 2830 if (value) { 2831 result = value.release(); 2832 return true; 2833 } 2834 return false; 2835} 2836 2837 2838 2839#if ENABLE(DASHBOARD_SUPPORT) 2840 2841#define DASHBOARD_REGION_NUM_PARAMETERS 6 2842#define DASHBOARD_REGION_SHORT_NUM_PARAMETERS 2 2843 2844static CSSParserValue* skipCommaInDashboardRegion(CSSParserValueList *args) 2845{ 2846 if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) || 2847 args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) { 2848 CSSParserValue* current = args->current(); 2849 if (current->unit == CSSParserValue::Operator && current->iValue == ',') 2850 return args->next(); 2851 } 2852 return args->current(); 2853} 2854 2855bool CSSParser::parseDashboardRegions(int propId, bool important) 2856{ 2857 bool valid = true; 2858 2859 CSSParserValue* value = m_valueList->current(); 2860 2861 if (value->id == CSSValueNone) { 2862 if (m_valueList->next()) 2863 return false; 2864 addProperty(propId, CSSPrimitiveValue::createIdentifier(value->id), important); 2865 return valid; 2866 } 2867 2868 RefPtr<DashboardRegion> firstRegion = DashboardRegion::create(); 2869 DashboardRegion* region = 0; 2870 2871 while (value) { 2872 if (region == 0) { 2873 region = firstRegion.get(); 2874 } else { 2875 RefPtr<DashboardRegion> nextRegion = DashboardRegion::create(); 2876 region->m_next = nextRegion; 2877 region = nextRegion.get(); 2878 } 2879 2880 if (value->unit != CSSParserValue::Function) { 2881 valid = false; 2882 break; 2883 } 2884 2885 // Commas count as values, so allow: 2886 // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l) 2887 // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l) 2888 // also allow 2889 // dashboard-region(label, type) or dashboard-region(label type) 2890 // dashboard-region(label, type) or dashboard-region(label type) 2891 CSSParserValueList* args = value->function->args; 2892 if (!equalIgnoringCase(value->function->name, "dashboard-region(") || !args) { 2893 valid = false; 2894 break; 2895 } 2896 2897 int numArgs = args->size(); 2898 if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) && 2899 (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))) { 2900 valid = false; 2901 break; 2902 } 2903 2904 // First arg is a label. 2905 CSSParserValue* arg = args->current(); 2906 if (arg->unit != CSSPrimitiveValue::CSS_IDENT) { 2907 valid = false; 2908 break; 2909 } 2910 2911 region->m_label = arg->string; 2912 2913 // Second arg is a type. 2914 arg = args->next(); 2915 arg = skipCommaInDashboardRegion(args); 2916 if (arg->unit != CSSPrimitiveValue::CSS_IDENT) { 2917 valid = false; 2918 break; 2919 } 2920 2921 if (equalIgnoringCase(arg->string, "circle")) 2922 region->m_isCircle = true; 2923 else if (equalIgnoringCase(arg->string, "rectangle")) 2924 region->m_isRectangle = true; 2925 else { 2926 valid = false; 2927 break; 2928 } 2929 2930 region->m_geometryType = arg->string; 2931 2932 if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) { 2933 // This originally used CSSValueInvalid by accident. It might be more logical to use something else. 2934 RefPtr<CSSPrimitiveValue> amount = CSSPrimitiveValue::createIdentifier(CSSValueInvalid); 2935 2936 region->setTop(amount); 2937 region->setRight(amount); 2938 region->setBottom(amount); 2939 region->setLeft(amount); 2940 } else { 2941 // Next four arguments must be offset numbers 2942 int i; 2943 for (i = 0; i < 4; i++) { 2944 arg = args->next(); 2945 arg = skipCommaInDashboardRegion(args); 2946 2947 valid = arg->id == CSSValueAuto || validUnit(arg, FLength, m_strict); 2948 if (!valid) 2949 break; 2950 2951 RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ? 2952 CSSPrimitiveValue::createIdentifier(CSSValueAuto) : 2953 CSSPrimitiveValue::create(arg->fValue, (CSSPrimitiveValue::UnitTypes) arg->unit); 2954 2955 if (i == 0) 2956 region->setTop(amount); 2957 else if (i == 1) 2958 region->setRight(amount); 2959 else if (i == 2) 2960 region->setBottom(amount); 2961 else 2962 region->setLeft(amount); 2963 } 2964 } 2965 2966 if (args->next()) 2967 return false; 2968 2969 value = m_valueList->next(); 2970 } 2971 2972 if (valid) 2973 addProperty(propId, CSSPrimitiveValue::create(firstRegion.release()), important); 2974 2975 return valid; 2976} 2977 2978#endif /* ENABLE(DASHBOARD_SUPPORT) */ 2979 2980PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters) 2981{ 2982 unsigned numArgs = args->size(); 2983 if (counters && numArgs != 3 && numArgs != 5) 2984 return 0; 2985 if (!counters && numArgs != 1 && numArgs != 3) 2986 return 0; 2987 2988 CSSParserValue* i = args->current(); 2989 if (i->unit != CSSPrimitiveValue::CSS_IDENT) 2990 return 0; 2991 RefPtr<CSSPrimitiveValue> identifier = CSSPrimitiveValue::create(i->string, CSSPrimitiveValue::CSS_STRING); 2992 2993 RefPtr<CSSPrimitiveValue> separator; 2994 if (!counters) 2995 separator = CSSPrimitiveValue::create(String(), CSSPrimitiveValue::CSS_STRING); 2996 else { 2997 i = args->next(); 2998 if (i->unit != CSSParserValue::Operator || i->iValue != ',') 2999 return 0; 3000 3001 i = args->next(); 3002 if (i->unit != CSSPrimitiveValue::CSS_STRING) 3003 return 0; 3004 3005 separator = CSSPrimitiveValue::create(i->string, (CSSPrimitiveValue::UnitTypes) i->unit); 3006 } 3007 3008 RefPtr<CSSPrimitiveValue> listStyle; 3009 i = args->next(); 3010 if (!i) // Make the list style default decimal 3011 listStyle = CSSPrimitiveValue::create(CSSValueDecimal - CSSValueDisc, CSSPrimitiveValue::CSS_NUMBER); 3012 else { 3013 if (i->unit != CSSParserValue::Operator || i->iValue != ',') 3014 return 0; 3015 3016 i = args->next(); 3017 if (i->unit != CSSPrimitiveValue::CSS_IDENT) 3018 return 0; 3019 3020 short ls = 0; 3021 if (i->id == CSSValueNone) 3022 ls = CSSValueKatakanaIroha - CSSValueDisc + 1; 3023 else if (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha) 3024 ls = i->id - CSSValueDisc; 3025 else 3026 return 0; 3027 3028 listStyle = CSSPrimitiveValue::create(ls, (CSSPrimitiveValue::UnitTypes) i->unit); 3029 } 3030 3031 return CSSPrimitiveValue::create(Counter::create(identifier.release(), listStyle.release(), separator.release())); 3032} 3033 3034bool CSSParser::parseShape(int propId, bool important) 3035{ 3036 CSSParserValue* value = m_valueList->current(); 3037 CSSParserValueList* args = value->function->args; 3038 3039 if (!equalIgnoringCase(value->function->name, "rect(") || !args) 3040 return false; 3041 3042 // rect(t, r, b, l) || rect(t r b l) 3043 if (args->size() != 4 && args->size() != 7) 3044 return false; 3045 RefPtr<Rect> rect = Rect::create(); 3046 bool valid = true; 3047 int i = 0; 3048 CSSParserValue* a = args->current(); 3049 while (a) { 3050 valid = a->id == CSSValueAuto || validUnit(a, FLength, m_strict); 3051 if (!valid) 3052 break; 3053 RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ? 3054 CSSPrimitiveValue::createIdentifier(CSSValueAuto) : 3055 CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit); 3056 if (i == 0) 3057 rect->setTop(length); 3058 else if (i == 1) 3059 rect->setRight(length); 3060 else if (i == 2) 3061 rect->setBottom(length); 3062 else 3063 rect->setLeft(length); 3064 a = args->next(); 3065 if (a && args->size() == 7) { 3066 if (a->unit == CSSParserValue::Operator && a->iValue == ',') { 3067 a = args->next(); 3068 } else { 3069 valid = false; 3070 break; 3071 } 3072 } 3073 i++; 3074 } 3075 if (valid) { 3076 addProperty(propId, CSSPrimitiveValue::create(rect.release()), important); 3077 m_valueList->next(); 3078 return true; 3079 } 3080 return false; 3081} 3082 3083// [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family' 3084bool CSSParser::parseFont(bool important) 3085{ 3086 bool valid = true; 3087 CSSParserValue *value = m_valueList->current(); 3088 RefPtr<FontValue> font = FontValue::create(); 3089 // optional font-style, font-variant and font-weight 3090 while (value) { 3091 int id = value->id; 3092 if (id) { 3093 if (id == CSSValueNormal) { 3094 // do nothing, it's the inital value for all three 3095 } else if (id == CSSValueItalic || id == CSSValueOblique) { 3096 if (font->style) 3097 return false; 3098 font->style = CSSPrimitiveValue::createIdentifier(id); 3099 } else if (id == CSSValueSmallCaps) { 3100 if (font->variant) 3101 return false; 3102 font->variant = CSSPrimitiveValue::createIdentifier(id); 3103 } else if (id >= CSSValueBold && id <= CSSValueLighter) { 3104 if (font->weight) 3105 return false; 3106 font->weight = CSSPrimitiveValue::createIdentifier(id); 3107 } else { 3108 valid = false; 3109 } 3110 } else if (!font->weight && validUnit(value, FInteger | FNonNeg, true)) { 3111 int weight = (int)value->fValue; 3112 int val = 0; 3113 if (weight == 100) 3114 val = CSSValue100; 3115 else if (weight == 200) 3116 val = CSSValue200; 3117 else if (weight == 300) 3118 val = CSSValue300; 3119 else if (weight == 400) 3120 val = CSSValue400; 3121 else if (weight == 500) 3122 val = CSSValue500; 3123 else if (weight == 600) 3124 val = CSSValue600; 3125 else if (weight == 700) 3126 val = CSSValue700; 3127 else if (weight == 800) 3128 val = CSSValue800; 3129 else if (weight == 900) 3130 val = CSSValue900; 3131 3132 if (val) 3133 font->weight = CSSPrimitiveValue::createIdentifier(val); 3134 else 3135 valid = false; 3136 } else { 3137 valid = false; 3138 } 3139 if (!valid) 3140 break; 3141 value = m_valueList->next(); 3142 } 3143 if (!value) 3144 return false; 3145 3146 // set undefined values to default 3147 if (!font->style) 3148 font->style = CSSPrimitiveValue::createIdentifier(CSSValueNormal); 3149 if (!font->variant) 3150 font->variant = CSSPrimitiveValue::createIdentifier(CSSValueNormal); 3151 if (!font->weight) 3152 font->weight = CSSPrimitiveValue::createIdentifier(CSSValueNormal); 3153 3154 // now a font size _must_ come 3155 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit 3156 if (value->id >= CSSValueXxSmall && value->id <= CSSValueLarger) 3157 font->size = CSSPrimitiveValue::createIdentifier(value->id); 3158 else if (validUnit(value, FLength | FPercent | FNonNeg, m_strict)) 3159 font->size = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); 3160 value = m_valueList->next(); 3161 if (!font->size || !value) 3162 return false; 3163 3164 if (value->unit == CSSParserValue::Operator && value->iValue == '/') { 3165 // line-height 3166 value = m_valueList->next(); 3167 if (!value) 3168 return false; 3169 if (value->id == CSSValueNormal) { 3170 // default value, nothing to do 3171 } else if (validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict)) 3172 font->lineHeight = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); 3173 else 3174 return false; 3175 value = m_valueList->next(); 3176 if (!value) 3177 return false; 3178 } 3179 3180 if (!font->lineHeight) 3181 font->lineHeight = CSSPrimitiveValue::createIdentifier(CSSValueNormal); 3182 3183 // font family must come now 3184 font->family = parseFontFamily(); 3185 3186 if (m_valueList->current() || !font->family) 3187 return false; 3188 3189 addProperty(CSSPropertyFont, font.release(), important); 3190 return true; 3191} 3192 3193PassRefPtr<CSSValueList> CSSParser::parseFontFamily() 3194{ 3195 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); 3196 CSSParserValue* value = m_valueList->current(); 3197 3198 FontFamilyValue* currFamily = 0; 3199 while (value) { 3200 CSSParserValue* nextValue = m_valueList->next(); 3201 bool nextValBreaksFont = !nextValue || 3202 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ','); 3203 bool nextValIsFontName = nextValue && 3204 ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) || 3205 (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT)); 3206 3207 if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) { 3208 if (currFamily) 3209 currFamily->appendSpaceSeparated(value->string.characters, value->string.length); 3210 else if (nextValBreaksFont || !nextValIsFontName) 3211 list->append(CSSPrimitiveValue::createIdentifier(value->id)); 3212 else { 3213 RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string); 3214 currFamily = newFamily.get(); 3215 list->append(newFamily.release()); 3216 } 3217 } else if (value->unit == CSSPrimitiveValue::CSS_STRING) { 3218 // Strings never share in a family name. 3219 currFamily = 0; 3220 list->append(FontFamilyValue::create(value->string)); 3221 } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) { 3222 if (currFamily) 3223 currFamily->appendSpaceSeparated(value->string.characters, value->string.length); 3224 else if (nextValBreaksFont || !nextValIsFontName) 3225 list->append(FontFamilyValue::create(value->string)); 3226 else { 3227 RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string); 3228 currFamily = newFamily.get(); 3229 list->append(newFamily.release()); 3230 } 3231 } else { 3232 break; 3233 } 3234 3235 if (!nextValue) 3236 break; 3237 3238 if (nextValBreaksFont) { 3239 value = m_valueList->next(); 3240 currFamily = 0; 3241 } 3242 else if (nextValIsFontName) 3243 value = nextValue; 3244 else 3245 break; 3246 } 3247 if (!list->length()) 3248 list = 0; 3249 return list.release(); 3250} 3251 3252bool CSSParser::parseFontStyle(bool important) 3253{ 3254 RefPtr<CSSValueList> values; 3255 if (m_valueList->size() > 1) 3256 values = CSSValueList::createCommaSeparated(); 3257 CSSParserValue* val; 3258 bool expectComma = false; 3259 while ((val = m_valueList->current())) { 3260 RefPtr<CSSPrimitiveValue> parsedValue; 3261 if (!expectComma) { 3262 expectComma = true; 3263 if (val->id == CSSValueNormal || val->id == CSSValueItalic || val->id == CSSValueOblique) 3264 parsedValue = CSSPrimitiveValue::createIdentifier(val->id); 3265 else if (val->id == CSSValueAll && !values) { 3266 // 'all' is only allowed in @font-face and with no other values. Make a value list to 3267 // indicate that we are in the @font-face case. 3268 values = CSSValueList::createCommaSeparated(); 3269 parsedValue = CSSPrimitiveValue::createIdentifier(val->id); 3270 } 3271 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') { 3272 expectComma = false; 3273 m_valueList->next(); 3274 continue; 3275 } 3276 3277 if (!parsedValue) 3278 return false; 3279 3280 m_valueList->next(); 3281 3282 if (values) 3283 values->append(parsedValue.release()); 3284 else { 3285 addProperty(CSSPropertyFontStyle, parsedValue.release(), important); 3286 return true; 3287 } 3288 } 3289 3290 if (values && values->length()) { 3291 m_hasFontFaceOnlyValues = true; 3292 addProperty(CSSPropertyFontStyle, values.release(), important); 3293 return true; 3294 } 3295 3296 return false; 3297} 3298 3299bool CSSParser::parseFontVariant(bool important) 3300{ 3301 RefPtr<CSSValueList> values; 3302 if (m_valueList->size() > 1) 3303 values = CSSValueList::createCommaSeparated(); 3304 CSSParserValue* val; 3305 bool expectComma = false; 3306 while ((val = m_valueList->current())) { 3307 RefPtr<CSSPrimitiveValue> parsedValue; 3308 if (!expectComma) { 3309 expectComma = true; 3310 if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps) 3311 parsedValue = CSSPrimitiveValue::createIdentifier(val->id); 3312 else if (val->id == CSSValueAll && !values) { 3313 // 'all' is only allowed in @font-face and with no other values. Make a value list to 3314 // indicate that we are in the @font-face case. 3315 values = CSSValueList::createCommaSeparated(); 3316 parsedValue = CSSPrimitiveValue::createIdentifier(val->id); 3317 } 3318 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') { 3319 expectComma = false; 3320 m_valueList->next(); 3321 continue; 3322 } 3323 3324 if (!parsedValue) 3325 return false; 3326 3327 m_valueList->next(); 3328 3329 if (values) 3330 values->append(parsedValue.release()); 3331 else { 3332 addProperty(CSSPropertyFontVariant, parsedValue.release(), important); 3333 return true; 3334 } 3335 } 3336 3337 if (values && values->length()) { 3338 m_hasFontFaceOnlyValues = true; 3339 addProperty(CSSPropertyFontVariant, values.release(), important); 3340 return true; 3341 } 3342 3343 return false; 3344} 3345 3346bool CSSParser::parseFontWeight(bool important) 3347{ 3348 RefPtr<CSSValueList> values; 3349 if (m_valueList->size() > 1) 3350 values = CSSValueList::createCommaSeparated(); 3351 CSSParserValue* val; 3352 bool expectComma = false; 3353 while ((val = m_valueList->current())) { 3354 RefPtr<CSSPrimitiveValue> parsedValue; 3355 if (!expectComma) { 3356 expectComma = true; 3357 if (val->unit == CSSPrimitiveValue::CSS_IDENT) { 3358 if (val->id >= CSSValueNormal && val->id <= CSSValue900) 3359 parsedValue = CSSPrimitiveValue::createIdentifier(val->id); 3360 else if (val->id == CSSValueAll && !values) { 3361 // 'all' is only allowed in @font-face and with no other values. Make a value list to 3362 // indicate that we are in the @font-face case. 3363 values = CSSValueList::createCommaSeparated(); 3364 parsedValue = CSSPrimitiveValue::createIdentifier(val->id); 3365 } 3366 } else if (validUnit(val, FInteger | FNonNeg, false)) { 3367 int weight = static_cast<int>(val->fValue); 3368 if (!(weight % 100) && weight >= 100 && weight <= 900) 3369 parsedValue = CSSPrimitiveValue::createIdentifier(CSSValue100 + weight / 100 - 1); 3370 } 3371 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') { 3372 expectComma = false; 3373 m_valueList->next(); 3374 continue; 3375 } 3376 3377 if (!parsedValue) 3378 return false; 3379 3380 m_valueList->next(); 3381 3382 if (values) 3383 values->append(parsedValue.release()); 3384 else { 3385 addProperty(CSSPropertyFontWeight, parsedValue.release(), important); 3386 return true; 3387 } 3388 } 3389 3390 if (values && values->length()) { 3391 m_hasFontFaceOnlyValues = true; 3392 addProperty(CSSPropertyFontWeight, values.release(), important); 3393 return true; 3394 } 3395 3396 return false; 3397} 3398 3399static bool isValidFormatFunction(CSSParserValue* val) 3400{ 3401 CSSParserValueList* args = val->function->args; 3402 return equalIgnoringCase(val->function->name, "format(") && (args->current()->unit == CSSPrimitiveValue::CSS_STRING || args->current()->unit == CSSPrimitiveValue::CSS_IDENT); 3403} 3404 3405bool CSSParser::parseFontFaceSrc() 3406{ 3407 RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated()); 3408 CSSParserValue* val; 3409 bool expectComma = false; 3410 bool allowFormat = false; 3411 bool failed = false; 3412 RefPtr<CSSFontFaceSrcValue> uriValue; 3413 while ((val = m_valueList->current())) { 3414 RefPtr<CSSFontFaceSrcValue> parsedValue; 3415 if (val->unit == CSSPrimitiveValue::CSS_URI && !expectComma && m_styleSheet) { 3416 // FIXME: The completeURL call should be done when using the CSSFontFaceSrcValue, 3417 // not when creating it. 3418 parsedValue = CSSFontFaceSrcValue::create(m_styleSheet->completeURL(val->string)); 3419 uriValue = parsedValue; 3420 allowFormat = true; 3421 expectComma = true; 3422 } else if (val->unit == CSSParserValue::Function) { 3423 // There are two allowed functions: local() and format(). 3424 CSSParserValueList* args = val->function->args; 3425 if (args && args->size() == 1) { 3426 if (equalIgnoringCase(val->function->name, "local(") && !expectComma) { 3427 expectComma = true; 3428 allowFormat = false; 3429 CSSParserValue* a = args->current(); 3430 uriValue.clear(); 3431 parsedValue = CSSFontFaceSrcValue::createLocal(a->string); 3432 } else if (allowFormat && uriValue && isValidFormatFunction(val)) { 3433 expectComma = true; 3434 allowFormat = false; 3435 uriValue->setFormat(args->current()->string); 3436 uriValue.clear(); 3437 m_valueList->next(); 3438 continue; 3439 } 3440 } 3441 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',' && expectComma) { 3442 expectComma = false; 3443 allowFormat = false; 3444 uriValue.clear(); 3445 m_valueList->next(); 3446 continue; 3447 } 3448 3449 if (parsedValue) 3450 values->append(parsedValue.release()); 3451 else { 3452 failed = true; 3453 break; 3454 } 3455 m_valueList->next(); 3456 } 3457 3458 if (values->length() && !failed) { 3459 addProperty(CSSPropertySrc, values.release(), m_important); 3460 m_valueList->next(); 3461 return true; 3462 } 3463 3464 return false; 3465} 3466 3467bool CSSParser::parseFontFaceUnicodeRange() 3468{ 3469 RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated(); 3470 CSSParserValue* currentValue; 3471 bool failed = false; 3472 while ((currentValue = m_valueList->current())) { 3473 if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) { 3474 failed = true; 3475 break; 3476 } 3477 3478 String rangeString = m_valueList->current()->string; 3479 UChar32 from = 0; 3480 UChar32 to = 0; 3481 unsigned length = rangeString.length(); 3482 3483 if (length < 3) { 3484 failed = true; 3485 break; 3486 } 3487 3488 unsigned i = 2; 3489 while (i < length) { 3490 UChar c = rangeString[i]; 3491 if (c == '-' || c == '?') 3492 break; 3493 from *= 16; 3494 if (c >= '0' && c <= '9') 3495 from += c - '0'; 3496 else if (c >= 'A' && c <= 'F') 3497 from += 10 + c - 'A'; 3498 else if (c >= 'a' && c <= 'f') 3499 from += 10 + c - 'a'; 3500 else { 3501 failed = true; 3502 break; 3503 } 3504 i++; 3505 } 3506 if (failed) 3507 break; 3508 3509 if (i == length) 3510 to = from; 3511 else if (rangeString[i] == '?') { 3512 unsigned span = 1; 3513 while (i < length && rangeString[i] == '?') { 3514 span *= 16; 3515 from *= 16; 3516 i++; 3517 } 3518 if (i < length) 3519 failed = true; 3520 to = from + span - 1; 3521 } else { 3522 if (length < i + 2) { 3523 failed = true; 3524 break; 3525 } 3526 i++; 3527 while (i < length) { 3528 UChar c = rangeString[i]; 3529 to *= 16; 3530 if (c >= '0' && c <= '9') 3531 to += c - '0'; 3532 else if (c >= 'A' && c <= 'F') 3533 to += 10 + c - 'A'; 3534 else if (c >= 'a' && c <= 'f') 3535 to += 10 + c - 'a'; 3536 else { 3537 failed = true; 3538 break; 3539 } 3540 i++; 3541 } 3542 if (failed) 3543 break; 3544 } 3545 values->append(CSSUnicodeRangeValue::create(from, to)); 3546 m_valueList->next(); 3547 } 3548 if (failed || !values->length()) 3549 return false; 3550 addProperty(CSSPropertyUnicodeRange, values.release(), m_important); 3551 return true; 3552} 3553 3554bool CSSParser::parseColor(const String &name, RGBA32& rgb, bool strict) 3555{ 3556 if (!strict && Color::parseHexColor(name, rgb)) 3557 return true; 3558 3559 // try a little harder 3560 Color tc; 3561 tc.setNamedColor(name); 3562 if (tc.isValid()) { 3563 rgb = tc.rgb(); 3564 return true; 3565 } 3566 3567 return false; 3568} 3569 3570bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha) 3571{ 3572 CSSParserValueList* args = value->function->args; 3573 CSSParserValue* v = args->current(); 3574 Units unitType = FUnknown; 3575 // Get the first value and its type 3576 if (validUnit(v, FInteger, true)) 3577 unitType = FInteger; 3578 else if (validUnit(v, FPercent, true)) 3579 unitType = FPercent; 3580 else 3581 return false; 3582 colorArray[0] = static_cast<int>(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.0)); 3583 for (int i = 1; i < 3; i++) { 3584 v = args->next(); 3585 if (v->unit != CSSParserValue::Operator && v->iValue != ',') 3586 return false; 3587 v = args->next(); 3588 if (!validUnit(v, unitType, true)) 3589 return false; 3590 colorArray[i] = static_cast<int>(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.0)); 3591 } 3592 if (parseAlpha) { 3593 v = args->next(); 3594 if (v->unit != CSSParserValue::Operator && v->iValue != ',') 3595 return false; 3596 v = args->next(); 3597 if (!validUnit(v, FNumber, true)) 3598 return false; 3599 colorArray[3] = static_cast<int>(max(0.0, min(1.0, v->fValue)) * 255); 3600 } 3601 return true; 3602} 3603 3604// The CSS3 specification defines the format of a HSL color as 3605// hsl(<number>, <percent>, <percent>) 3606// and with alpha, the format is 3607// hsla(<number>, <percent>, <percent>, <number>) 3608// The first value, HUE, is in an angle with a value between 0 and 360 3609bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha) 3610{ 3611 CSSParserValueList* args = value->function->args; 3612 CSSParserValue* v = args->current(); 3613 // Get the first value 3614 if (!validUnit(v, FNumber, true)) 3615 return false; 3616 // normalize the Hue value and change it to be between 0 and 1.0 3617 colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0; 3618 for (int i = 1; i < 3; i++) { 3619 v = args->next(); 3620 if (v->unit != CSSParserValue::Operator && v->iValue != ',') 3621 return false; 3622 v = args->next(); 3623 if (!validUnit(v, FPercent, true)) 3624 return false; 3625 colorArray[i] = max(0.0, min(100.0, v->fValue)) / 100.0; // needs to be value between 0 and 1.0 3626 } 3627 if (parseAlpha) { 3628 v = args->next(); 3629 if (v->unit != CSSParserValue::Operator && v->iValue != ',') 3630 return false; 3631 v = args->next(); 3632 if (!validUnit(v, FNumber, true)) 3633 return false; 3634 colorArray[3] = max(0.0, min(1.0, v->fValue)); 3635 } 3636 return true; 3637} 3638 3639PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value) 3640{ 3641 RGBA32 c = Color::transparent; 3642 if (!parseColorFromValue(value ? value : m_valueList->current(), c)) 3643 return 0; 3644 return CSSPrimitiveValue::createColor(c); 3645} 3646 3647bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c, bool svg) 3648{ 3649 if (!m_strict && value->unit == CSSPrimitiveValue::CSS_NUMBER && 3650 value->fValue >= 0. && value->fValue < 1000000.) { 3651 String str = String::format("%06d", (int)(value->fValue+.5)); 3652 if (!CSSParser::parseColor(str, c, m_strict)) 3653 return false; 3654 } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR || 3655 value->unit == CSSPrimitiveValue::CSS_IDENT || 3656 (!m_strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) { 3657 if (!CSSParser::parseColor(value->string, c, m_strict && value->unit == CSSPrimitiveValue::CSS_IDENT)) 3658 return false; 3659 } else if (value->unit == CSSParserValue::Function && 3660 value->function->args != 0 && 3661 value->function->args->size() == 5 /* rgb + two commas */ && 3662 equalIgnoringCase(value->function->name, "rgb(")) { 3663 int colorValues[3]; 3664 if (!parseColorParameters(value, colorValues, false)) 3665 return false; 3666 c = makeRGB(colorValues[0], colorValues[1], colorValues[2]); 3667 } else if (!svg) { 3668 if (value->unit == CSSParserValue::Function && 3669 value->function->args != 0 && 3670 value->function->args->size() == 7 /* rgba + three commas */ && 3671 equalIgnoringCase(value->function->name, "rgba(")) { 3672 int colorValues[4]; 3673 if (!parseColorParameters(value, colorValues, true)) 3674 return false; 3675 c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]); 3676 } else if (value->unit == CSSParserValue::Function && 3677 value->function->args != 0 && 3678 value->function->args->size() == 5 /* hsl + two commas */ && 3679 equalIgnoringCase(value->function->name, "hsl(")) { 3680 double colorValues[3]; 3681 if (!parseHSLParameters(value, colorValues, false)) 3682 return false; 3683 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0); 3684 } else if (value->unit == CSSParserValue::Function && 3685 value->function->args != 0 && 3686 value->function->args->size() == 7 /* hsla + three commas */ && 3687 equalIgnoringCase(value->function->name, "hsla(")) { 3688 double colorValues[4]; 3689 if (!parseHSLParameters(value, colorValues, true)) 3690 return false; 3691 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]); 3692 } else 3693 return false; 3694 } else 3695 return false; 3696 3697 return true; 3698} 3699 3700// This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return) 3701// without the allowBreak bit being set, then it will clean up all of the objects and destroy them. 3702struct ShadowParseContext { 3703 ShadowParseContext(CSSPropertyID prop) 3704 : property(prop) 3705 , allowX(true) 3706 , allowY(false) 3707 , allowBlur(false) 3708 , allowSpread(false) 3709 , allowColor(true) 3710 , allowStyle(prop == CSSPropertyWebkitBoxShadow) 3711 , allowBreak(true) 3712 { 3713 } 3714 3715 bool allowLength() { return allowX || allowY || allowBlur || allowSpread; } 3716 3717 void commitValue() 3718 { 3719 // Handle the ,, case gracefully by doing nothing. 3720 if (x || y || blur || spread || color || style) { 3721 if (!values) 3722 values = CSSValueList::createCommaSeparated(); 3723 3724 // Construct the current shadow value and add it to the list. 3725 values->append(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release())); 3726 } 3727 3728 // Now reset for the next shadow value. 3729 x = 0; 3730 y = 0; 3731 blur = 0; 3732 spread = 0; 3733 style = 0; 3734 color = 0; 3735 3736 allowX = true; 3737 allowColor = true; 3738 allowBreak = true; 3739 allowY = false; 3740 allowBlur = false; 3741 allowSpread = false; 3742 allowStyle = property == CSSPropertyWebkitBoxShadow; 3743 } 3744 3745 void commitLength(CSSParserValue* v) 3746 { 3747 RefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit); 3748 3749 if (allowX) { 3750 x = val.release(); 3751 allowX = false; 3752 allowY = true; 3753 allowColor = false; 3754 allowStyle = false; 3755 allowBreak = false; 3756 } else if (allowY) { 3757 y = val.release(); 3758 allowY = false; 3759 allowBlur = true; 3760 allowColor = true; 3761 allowStyle = property == CSSPropertyWebkitBoxShadow; 3762 allowBreak = true; 3763 } else if (allowBlur) { 3764 blur = val.release(); 3765 allowBlur = false; 3766 allowSpread = property == CSSPropertyWebkitBoxShadow; 3767 } else if (allowSpread) { 3768 spread = val.release(); 3769 allowSpread = false; 3770 } 3771 } 3772 3773 void commitColor(PassRefPtr<CSSPrimitiveValue> val) 3774 { 3775 color = val; 3776 allowColor = false; 3777 if (allowX) { 3778 allowStyle = false; 3779 allowBreak = false; 3780 } else { 3781 allowBlur = false; 3782 allowSpread = false; 3783 allowStyle = property == CSSPropertyWebkitBoxShadow; 3784 } 3785 } 3786 3787 void commitStyle(CSSParserValue* v) 3788 { 3789 style = CSSPrimitiveValue::createIdentifier(v->id); 3790 allowStyle = false; 3791 if (allowX) 3792 allowBreak = false; 3793 else { 3794 allowBlur = false; 3795 allowSpread = false; 3796 allowColor = false; 3797 } 3798 } 3799 3800 CSSPropertyID property; 3801 3802 RefPtr<CSSValueList> values; 3803 RefPtr<CSSPrimitiveValue> x; 3804 RefPtr<CSSPrimitiveValue> y; 3805 RefPtr<CSSPrimitiveValue> blur; 3806 RefPtr<CSSPrimitiveValue> spread; 3807 RefPtr<CSSPrimitiveValue> style; 3808 RefPtr<CSSPrimitiveValue> color; 3809 3810 bool allowX; 3811 bool allowY; 3812 bool allowBlur; 3813 bool allowSpread; 3814 bool allowColor; 3815 bool allowStyle; 3816 bool allowBreak; 3817}; 3818 3819bool CSSParser::parseShadow(int propId, bool important) 3820{ 3821 ShadowParseContext context(static_cast<CSSPropertyID>(propId)); 3822 CSSParserValue* val; 3823 while ((val = m_valueList->current())) { 3824 // Check for a comma break first. 3825 if (val->unit == CSSParserValue::Operator) { 3826 if (val->iValue != ',' || !context.allowBreak) 3827 // Other operators aren't legal or we aren't done with the current shadow 3828 // value. Treat as invalid. 3829 return false; 3830#if ENABLE(SVG) 3831 // -webkit-svg-shadow does not support multiple values. 3832 if (static_cast<CSSPropertyID>(propId) == CSSPropertyWebkitSvgShadow) 3833 return false; 3834#endif 3835 // The value is good. Commit it. 3836 context.commitValue(); 3837 } else if (validUnit(val, FLength, true)) { 3838 // We required a length and didn't get one. Invalid. 3839 if (!context.allowLength()) 3840 return false; 3841 3842 // A length is allowed here. Construct the value and add it. 3843 context.commitLength(val); 3844 } else if (val->id == CSSValueInset) { 3845 if (!context.allowStyle) 3846 return false; 3847 3848 context.commitStyle(val); 3849 } else { 3850 // The only other type of value that's ok is a color value. 3851 RefPtr<CSSPrimitiveValue> parsedColor; 3852 bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu || 3853 (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && !m_strict)); 3854 if (isColor) { 3855 if (!context.allowColor) 3856 return false; 3857 parsedColor = CSSPrimitiveValue::createIdentifier(val->id); 3858 } 3859 3860 if (!parsedColor) 3861 // It's not built-in. Try to parse it as a color. 3862 parsedColor = parseColor(val); 3863 3864 if (!parsedColor || !context.allowColor) 3865 return false; // This value is not a color or length and is invalid or 3866 // it is a color, but a color isn't allowed at this point. 3867 3868 context.commitColor(parsedColor.release()); 3869 } 3870 3871 m_valueList->next(); 3872 } 3873 3874 if (context.allowBreak) { 3875 context.commitValue(); 3876 if (context.values->length()) { 3877 addProperty(propId, context.values.release(), important); 3878 m_valueList->next(); 3879 return true; 3880 } 3881 } 3882 3883 return false; 3884} 3885 3886bool CSSParser::parseReflect(int propId, bool important) 3887{ 3888 // box-reflect: <direction> <offset> <mask> 3889 3890 // Direction comes first. 3891 CSSParserValue* val = m_valueList->current(); 3892 CSSReflectionDirection direction; 3893 switch (val->id) { 3894 case CSSValueAbove: 3895 direction = ReflectionAbove; 3896 break; 3897 case CSSValueBelow: 3898 direction = ReflectionBelow; 3899 break; 3900 case CSSValueLeft: 3901 direction = ReflectionLeft; 3902 break; 3903 case CSSValueRight: 3904 direction = ReflectionRight; 3905 break; 3906 default: 3907 return false; 3908 } 3909 3910 // The offset comes next. 3911 val = m_valueList->next(); 3912 RefPtr<CSSPrimitiveValue> offset; 3913 if (!val) 3914 offset = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_PX); 3915 else { 3916 if (!validUnit(val, FLength | FPercent, m_strict)) 3917 return false; 3918 offset = CSSPrimitiveValue::create(val->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(val->unit)); 3919 } 3920 3921 // Now for the mask. 3922 RefPtr<CSSValue> mask; 3923 val = m_valueList->next(); 3924 if (val) { 3925 if (!parseBorderImage(propId, important, mask)) 3926 return false; 3927 } 3928 3929 RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction, offset.release(), mask.release()); 3930 addProperty(propId, reflectValue.release(), important); 3931 m_valueList->next(); 3932 return true; 3933} 3934 3935struct BorderImageParseContext { 3936 BorderImageParseContext() 3937 : m_allowBreak(false) 3938 , m_allowNumber(false) 3939 , m_allowSlash(false) 3940 , m_allowWidth(false) 3941 , m_allowRule(false) 3942 , m_borderTop(0) 3943 , m_borderRight(0) 3944 , m_borderBottom(0) 3945 , m_borderLeft(0) 3946 , m_horizontalRule(0) 3947 , m_verticalRule(0) 3948 {} 3949 3950 bool allowBreak() const { return m_allowBreak; } 3951 bool allowNumber() const { return m_allowNumber; } 3952 bool allowSlash() const { return m_allowSlash; } 3953 bool allowWidth() const { return m_allowWidth; } 3954 bool allowRule() const { return m_allowRule; } 3955 3956 void commitImage(PassRefPtr<CSSValue> image) { m_image = image; m_allowNumber = true; } 3957 void commitNumber(CSSParserValue* v) 3958 { 3959 PassRefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit); 3960 if (!m_top) 3961 m_top = val; 3962 else if (!m_right) 3963 m_right = val; 3964 else if (!m_bottom) 3965 m_bottom = val; 3966 else { 3967 ASSERT(!m_left); 3968 m_left = val; 3969 } 3970 3971 m_allowBreak = m_allowSlash = m_allowRule = true; 3972 m_allowNumber = !m_left; 3973 } 3974 void commitSlash() { m_allowBreak = m_allowSlash = m_allowNumber = false; m_allowWidth = true; } 3975 void commitWidth(CSSParserValue* val) 3976 { 3977 if (!m_borderTop) 3978 m_borderTop = val; 3979 else if (!m_borderRight) 3980 m_borderRight = val; 3981 else if (!m_borderBottom) 3982 m_borderBottom = val; 3983 else { 3984 ASSERT(!m_borderLeft); 3985 m_borderLeft = val; 3986 } 3987 3988 m_allowBreak = m_allowRule = true; 3989 m_allowWidth = !m_borderLeft; 3990 } 3991 void commitRule(int keyword) 3992 { 3993 if (!m_horizontalRule) 3994 m_horizontalRule = keyword; 3995 else if (!m_verticalRule) 3996 m_verticalRule = keyword; 3997 m_allowRule = !m_verticalRule; 3998 } 3999 PassRefPtr<CSSValue> commitBorderImage(CSSParser* p, bool important) 4000 { 4001 // We need to clone and repeat values for any omissions. 4002 if (!m_right) { 4003 m_right = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); 4004 m_bottom = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); 4005 m_left = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); 4006 } 4007 if (!m_bottom) { 4008 m_bottom = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); 4009 m_left = CSSPrimitiveValue::create(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType()); 4010 } 4011 if (!m_left) 4012 m_left = CSSPrimitiveValue::create(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType()); 4013 4014 // Now build a rect value to hold all four of our primitive values. 4015 RefPtr<Rect> rect = Rect::create(); 4016 rect->setTop(m_top); 4017 rect->setRight(m_right); 4018 rect->setBottom(m_bottom); 4019 rect->setLeft(m_left); 4020 4021 // Fill in STRETCH as the default if it wasn't specified. 4022 if (!m_horizontalRule) 4023 m_horizontalRule = CSSValueStretch; 4024 4025 // The vertical rule should match the horizontal rule if unspecified. 4026 if (!m_verticalRule) 4027 m_verticalRule = m_horizontalRule; 4028 4029 // 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 4030 // list and then make our parsing machinery do the parsing. 4031 if (m_borderTop) { 4032 CSSParserValueList newList; 4033 newList.addValue(*m_borderTop); 4034 if (m_borderRight) 4035 newList.addValue(*m_borderRight); 4036 if (m_borderBottom) 4037 newList.addValue(*m_borderBottom); 4038 if (m_borderLeft) 4039 newList.addValue(*m_borderLeft); 4040 CSSParserValueList* oldList = p->m_valueList; 4041 p->m_valueList = &newList; 4042 p->parseValue(CSSPropertyBorderWidth, important); 4043 p->m_valueList = oldList; 4044 } 4045 4046 // Make our new border image value now. 4047 return CSSBorderImageValue::create(m_image, rect.release(), m_horizontalRule, m_verticalRule); 4048 } 4049 4050 bool m_allowBreak; 4051 bool m_allowNumber; 4052 bool m_allowSlash; 4053 bool m_allowWidth; 4054 bool m_allowRule; 4055 4056 RefPtr<CSSValue> m_image; 4057 4058 RefPtr<CSSPrimitiveValue> m_top; 4059 RefPtr<CSSPrimitiveValue> m_right; 4060 RefPtr<CSSPrimitiveValue> m_bottom; 4061 RefPtr<CSSPrimitiveValue> m_left; 4062 4063 CSSParserValue* m_borderTop; 4064 CSSParserValue* m_borderRight; 4065 CSSParserValue* m_borderBottom; 4066 CSSParserValue* m_borderLeft; 4067 4068 int m_horizontalRule; 4069 int m_verticalRule; 4070}; 4071 4072bool CSSParser::parseBorderImage(int propId, bool important, RefPtr<CSSValue>& result) 4073{ 4074 // Look for an image initially. If the first value is not a URI, then we're done. 4075 BorderImageParseContext context; 4076 CSSParserValue* val = m_valueList->current(); 4077 if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) { 4078 // FIXME: The completeURL call should be done when using the CSSImageValue, 4079 // not when creating it. 4080 context.commitImage(CSSImageValue::create(m_styleSheet->completeURL(val->string))); 4081 } else if (val->unit == CSSParserValue::Function) { 4082 RefPtr<CSSValue> value; 4083 if ((equalIgnoringCase(val->function->name, "-webkit-gradient(") && parseGradient(value)) || 4084 (equalIgnoringCase(val->function->name, "-webkit-canvas(") && parseCanvas(value))) 4085 context.commitImage(value); 4086 else 4087 return false; 4088 } else 4089 return false; 4090 4091 while ((val = m_valueList->next())) { 4092 if (context.allowNumber() && validUnit(val, FInteger | FNonNeg | FPercent, true)) { 4093 context.commitNumber(val); 4094 } else if (propId == CSSPropertyWebkitBorderImage && context.allowSlash() && val->unit == CSSParserValue::Operator && val->iValue == '/') { 4095 context.commitSlash(); 4096 } else if (context.allowWidth() && 4097 (val->id == CSSValueThin || val->id == CSSValueMedium || val->id == CSSValueThick || validUnit(val, FLength, m_strict))) { 4098 context.commitWidth(val); 4099 } else if (context.allowRule() && 4100 (val->id == CSSValueStretch || val->id == CSSValueRound || val->id == CSSValueRepeat)) { 4101 context.commitRule(val->id); 4102 } else { 4103 // Something invalid was encountered. 4104 return false; 4105 } 4106 } 4107 4108 if (context.allowNumber() && propId != CSSPropertyWebkitBorderImage) { 4109 // Allow the slices to be omitted for images that don't fit to a border. We just set the slices to be 0. 4110 context.m_top = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_NUMBER); 4111 context.m_allowBreak = true; 4112 } 4113 4114 if (context.allowBreak()) { 4115 // Need to fully commit as a single value. 4116 result = context.commitBorderImage(this, important); 4117 return true; 4118 } 4119 4120 return false; 4121} 4122 4123static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4]) 4124{ 4125 if (radii[3]) 4126 return; 4127 if (!radii[2]) { 4128 if (!radii[1]) 4129 radii[1] = radii[0]; 4130 radii[2] = radii[0]; 4131 } 4132 radii[3] = radii[1]; 4133} 4134 4135bool CSSParser::parseBorderRadius(int propId, bool important) 4136{ 4137 unsigned num = m_valueList->size(); 4138 if (num > 9) 4139 return false; 4140 4141 RefPtr<CSSPrimitiveValue> radii[2][4]; 4142 4143 unsigned indexAfterSlash = 0; 4144 for (unsigned i = 0; i < num; ++i) { 4145 CSSParserValue* value = m_valueList->valueAt(i); 4146 if (value->unit == CSSParserValue::Operator) { 4147 if (value->iValue != '/') 4148 return false; 4149 4150 if (!i || indexAfterSlash || i + 1 == num || num > i + 5) 4151 return false; 4152 4153 indexAfterSlash = i + 1; 4154 completeBorderRadii(radii[0]); 4155 continue; 4156 } 4157 4158 if (i - indexAfterSlash >= 4) 4159 return false; 4160 4161 if (!validUnit(value, FLength, m_strict)) 4162 return false; 4163 4164 RefPtr<CSSPrimitiveValue> radius = CSSPrimitiveValue::create(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)); 4165 4166 if (!indexAfterSlash) { 4167 radii[0][i] = radius; 4168 4169 // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2; 4170 if (num == 2 && propId == CSSPropertyWebkitBorderRadius) { 4171 indexAfterSlash = 1; 4172 completeBorderRadii(radii[0]); 4173 } 4174 } else 4175 radii[1][i - indexAfterSlash] = radius.release(); 4176 } 4177 4178 if (!indexAfterSlash) { 4179 completeBorderRadii(radii[0]); 4180 for (unsigned i = 0; i < 4; ++i) 4181 radii[1][i] = radii[0][i]; 4182 } else 4183 completeBorderRadii(radii[1]); 4184 4185 addProperty(CSSPropertyBorderTopLeftRadius, CSSPrimitiveValue::create(Pair::create(radii[0][0].release(), radii[1][0].release())), important); 4186 addProperty(CSSPropertyBorderTopRightRadius, CSSPrimitiveValue::create(Pair::create(radii[0][1].release(), radii[1][1].release())), important); 4187 addProperty(CSSPropertyBorderBottomRightRadius, CSSPrimitiveValue::create(Pair::create(radii[0][2].release(), radii[1][2].release())), important); 4188 addProperty(CSSPropertyBorderBottomLeftRadius, CSSPrimitiveValue::create(Pair::create(radii[0][3].release(), radii[1][3].release())), important); 4189 return true; 4190} 4191 4192bool CSSParser::parseCounter(int propId, int defaultValue, bool important) 4193{ 4194 enum { ID, VAL } state = ID; 4195 4196 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); 4197 RefPtr<CSSPrimitiveValue> counterName; 4198 4199 while (true) { 4200 CSSParserValue* val = m_valueList->current(); 4201 switch (state) { 4202 case ID: 4203 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) { 4204 counterName = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING); 4205 state = VAL; 4206 m_valueList->next(); 4207 continue; 4208 } 4209 break; 4210 case VAL: { 4211 int i = defaultValue; 4212 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) { 4213 i = (int)val->fValue; 4214 m_valueList->next(); 4215 } 4216 4217 list->append(CSSPrimitiveValue::create(Pair::create(counterName.release(), 4218 CSSPrimitiveValue::create(i, CSSPrimitiveValue::CSS_NUMBER)))); 4219 state = ID; 4220 continue; 4221 } 4222 } 4223 break; 4224 } 4225 4226 if (list->length() > 0) { 4227 addProperty(propId, list.release(), important); 4228 return true; 4229 } 4230 4231 return false; 4232} 4233 4234static PassRefPtr<CSSPrimitiveValue> parseGradientPoint(CSSParserValue* a, bool horizontal) 4235{ 4236 RefPtr<CSSPrimitiveValue> result; 4237 if (a->unit == CSSPrimitiveValue::CSS_IDENT) { 4238 if ((equalIgnoringCase(a->string, "left") && horizontal) || 4239 (equalIgnoringCase(a->string, "top") && !horizontal)) 4240 result = CSSPrimitiveValue::create(0., CSSPrimitiveValue::CSS_PERCENTAGE); 4241 else if ((equalIgnoringCase(a->string, "right") && horizontal) || 4242 (equalIgnoringCase(a->string, "bottom") && !horizontal)) 4243 result = CSSPrimitiveValue::create(100., CSSPrimitiveValue::CSS_PERCENTAGE); 4244 else if (equalIgnoringCase(a->string, "center")) 4245 result = CSSPrimitiveValue::create(50., CSSPrimitiveValue::CSS_PERCENTAGE); 4246 } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE) 4247 result = CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit); 4248 return result; 4249} 4250 4251static bool parseGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop) 4252{ 4253 if (a->unit != CSSParserValue::Function) 4254 return false; 4255 4256 if (!equalIgnoringCase(a->function->name, "from(") && 4257 !equalIgnoringCase(a->function->name, "to(") && 4258 !equalIgnoringCase(a->function->name, "color-stop(")) 4259 return false; 4260 4261 CSSParserValueList* args = a->function->args; 4262 if (!args) 4263 return false; 4264 4265 if (equalIgnoringCase(a->function->name, "from(") || 4266 equalIgnoringCase(a->function->name, "to(")) { 4267 // The "from" and "to" stops expect 1 argument. 4268 if (args->size() != 1) 4269 return false; 4270 4271 if (equalIgnoringCase(a->function->name, "from(")) 4272 stop.m_stop = 0.f; 4273 else 4274 stop.m_stop = 1.f; 4275 4276 int id = args->current()->id; 4277 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu) 4278 stop.m_color = CSSPrimitiveValue::createIdentifier(id); 4279 else 4280 stop.m_color = p->parseColor(args->current()); 4281 if (!stop.m_color) 4282 return false; 4283 } 4284 4285 // The "color-stop" function expects 3 arguments. 4286 if (equalIgnoringCase(a->function->name, "color-stop(")) { 4287 if (args->size() != 3) 4288 return false; 4289 4290 CSSParserValue* stopArg = args->current(); 4291 if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE) 4292 stop.m_stop = (float)stopArg->fValue / 100.f; 4293 else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER) 4294 stop.m_stop = (float)stopArg->fValue; 4295 else 4296 return false; 4297 4298 stopArg = args->next(); 4299 if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',') 4300 return false; 4301 4302 stopArg = args->next(); 4303 int id = stopArg->id; 4304 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu) 4305 stop.m_color = CSSPrimitiveValue::createIdentifier(id); 4306 else 4307 stop.m_color = p->parseColor(stopArg); 4308 if (!stop.m_color) 4309 return false; 4310 } 4311 4312 return true; 4313} 4314 4315bool CSSParser::parseGradient(RefPtr<CSSValue>& gradient) 4316{ 4317 RefPtr<CSSGradientValue> result = CSSGradientValue::create(); 4318 4319 // Walk the arguments. 4320 CSSParserValueList* args = m_valueList->current()->function->args; 4321 if (!args || args->size() == 0) 4322 return false; 4323 4324 // The first argument is the gradient type. It is an identifier. 4325 CSSParserValue* a = args->current(); 4326 if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT) 4327 return false; 4328 if (equalIgnoringCase(a->string, "linear")) 4329 result->setType(CSSLinearGradient); 4330 else if (equalIgnoringCase(a->string, "radial")) 4331 result->setType(CSSRadialGradient); 4332 else 4333 return false; 4334 4335 // Comma. 4336 a = args->next(); 4337 if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',') 4338 return false; 4339 4340 // Next comes the starting point for the gradient as an x y pair. There is no 4341 // comma between the x and the y values. 4342 // First X. It can be left, right, number or percent. 4343 a = args->next(); 4344 if (!a) 4345 return false; 4346 RefPtr<CSSPrimitiveValue> point = parseGradientPoint(a, true); 4347 if (!point) 4348 return false; 4349 result->setFirstX(point.release()); 4350 4351 // First Y. It can be top, bottom, number or percent. 4352 a = args->next(); 4353 if (!a) 4354 return false; 4355 point = parseGradientPoint(a, false); 4356 if (!point) 4357 return false; 4358 result->setFirstY(point.release()); 4359 4360 // Comma after the first point. 4361 a = args->next(); 4362 if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',') 4363 return false; 4364 4365 // For radial gradients only, we now expect a numeric radius. 4366 if (result->type() == CSSRadialGradient) { 4367 a = args->next(); 4368 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER) 4369 return false; 4370 result->setFirstRadius(CSSPrimitiveValue::create(a->fValue, CSSPrimitiveValue::CSS_NUMBER)); 4371 4372 // Comma after the first radius. 4373 a = args->next(); 4374 if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',') 4375 return false; 4376 } 4377 4378 // Next is the ending point for the gradient as an x, y pair. 4379 // Second X. It can be left, right, number or percent. 4380 a = args->next(); 4381 if (!a) 4382 return false; 4383 point = parseGradientPoint(a, true); 4384 if (!point) 4385 return false; 4386 result->setSecondX(point.release()); 4387 4388 // Second Y. It can be top, bottom, number or percent. 4389 a = args->next(); 4390 if (!a) 4391 return false; 4392 point = parseGradientPoint(a, false); 4393 if (!point) 4394 return false; 4395 result->setSecondY(point.release()); 4396 4397 // For radial gradients only, we now expect the second radius. 4398 if (result->type() == CSSRadialGradient) { 4399 // Comma after the second point. 4400 a = args->next(); 4401 if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',') 4402 return false; 4403 4404 a = args->next(); 4405 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER) 4406 return false; 4407 result->setSecondRadius(CSSPrimitiveValue::create(a->fValue, CSSPrimitiveValue::CSS_NUMBER)); 4408 } 4409 4410 // We now will accept any number of stops (0 or more). 4411 a = args->next(); 4412 while (a) { 4413 // Look for the comma before the next stop. 4414 if (a->unit != CSSParserValue::Operator || a->iValue != ',') 4415 return false; 4416 4417 // Now examine the stop itself. 4418 a = args->next(); 4419 if (!a) 4420 return false; 4421 4422 // The function name needs to be one of "from", "to", or "color-stop." 4423 CSSGradientColorStop stop; 4424 if (!parseGradientColorStop(this, a, stop)) 4425 return false; 4426 result->addStop(stop); 4427 4428 // Advance 4429 a = args->next(); 4430 } 4431 4432 gradient = result.release(); 4433 return true; 4434} 4435 4436bool CSSParser::parseCanvas(RefPtr<CSSValue>& canvas) 4437{ 4438 RefPtr<CSSCanvasValue> result = CSSCanvasValue::create(); 4439 4440 // Walk the arguments. 4441 CSSParserValueList* args = m_valueList->current()->function->args; 4442 if (!args || args->size() != 1) 4443 return false; 4444 4445 // The first argument is the canvas name. It is an identifier. 4446 CSSParserValue* a = args->current(); 4447 if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT) 4448 return false; 4449 result->setName(a->string); 4450 canvas = result; 4451 return true; 4452} 4453 4454class TransformOperationInfo { 4455public: 4456 TransformOperationInfo(const CSSParserString& name) 4457 : m_type(WebKitCSSTransformValue::UnknownTransformOperation) 4458 , m_argCount(1) 4459 , m_allowSingleArgument(false) 4460 , m_unit(CSSParser::FUnknown) 4461 { 4462 if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "scalex(") || equalIgnoringCase(name, "scaley(") || equalIgnoringCase(name, "scalez(")) { 4463 m_unit = CSSParser::FNumber; 4464 if (equalIgnoringCase(name, "scale(")) 4465 m_type = WebKitCSSTransformValue::ScaleTransformOperation; 4466 else if (equalIgnoringCase(name, "scalex(")) 4467 m_type = WebKitCSSTransformValue::ScaleXTransformOperation; 4468 else if (equalIgnoringCase(name, "scaley(")) 4469 m_type = WebKitCSSTransformValue::ScaleYTransformOperation; 4470 else 4471 m_type = WebKitCSSTransformValue::ScaleZTransformOperation; 4472 } else if (equalIgnoringCase(name, "scale3d(")) { 4473 m_type = WebKitCSSTransformValue::Scale3DTransformOperation; 4474 m_argCount = 5; 4475 m_unit = CSSParser::FNumber; 4476 } else if (equalIgnoringCase(name, "rotate(")) { 4477 m_type = WebKitCSSTransformValue::RotateTransformOperation; 4478 m_unit = CSSParser::FAngle; 4479 } else if (equalIgnoringCase(name, "rotatex(") || 4480 equalIgnoringCase(name, "rotatey(") || 4481 equalIgnoringCase(name, "rotatez(")) { 4482 m_unit = CSSParser::FAngle; 4483 if (equalIgnoringCase(name, "rotatex(")) 4484 m_type = WebKitCSSTransformValue::RotateXTransformOperation; 4485 else if (equalIgnoringCase(name, "rotatey(")) 4486 m_type = WebKitCSSTransformValue::RotateYTransformOperation; 4487 else 4488 m_type = WebKitCSSTransformValue::RotateZTransformOperation; 4489 } else if (equalIgnoringCase(name, "rotate3d(")) { 4490 m_type = WebKitCSSTransformValue::Rotate3DTransformOperation; 4491 m_argCount = 7; 4492 m_unit = CSSParser::FNumber; 4493 } else if (equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "skewx(") || equalIgnoringCase(name, "skewy(")) { 4494 m_unit = CSSParser::FAngle; 4495 if (equalIgnoringCase(name, "skew(")) 4496 m_type = WebKitCSSTransformValue::SkewTransformOperation; 4497 else if (equalIgnoringCase(name, "skewx(")) 4498 m_type = WebKitCSSTransformValue::SkewXTransformOperation; 4499 else 4500 m_type = WebKitCSSTransformValue::SkewYTransformOperation; 4501 } else if (equalIgnoringCase(name, "translate(") || equalIgnoringCase(name, "translatex(") || equalIgnoringCase(name, "translatey(") || equalIgnoringCase(name, "translatez(")) { 4502 m_unit = CSSParser::FLength | CSSParser::FPercent; 4503 if (equalIgnoringCase(name, "translate(")) 4504 m_type = WebKitCSSTransformValue::TranslateTransformOperation; 4505 else if (equalIgnoringCase(name, "translatex(")) 4506 m_type = WebKitCSSTransformValue::TranslateXTransformOperation; 4507 else if (equalIgnoringCase(name, "translatey(")) 4508 m_type = WebKitCSSTransformValue::TranslateYTransformOperation; 4509 else 4510 m_type = WebKitCSSTransformValue::TranslateZTransformOperation; 4511 } else if (equalIgnoringCase(name, "translate3d(")) { 4512 m_type = WebKitCSSTransformValue::Translate3DTransformOperation; 4513 m_argCount = 5; 4514 m_unit = CSSParser::FLength | CSSParser::FPercent; 4515 } else if (equalIgnoringCase(name, "matrix(")) { 4516 m_type = WebKitCSSTransformValue::MatrixTransformOperation; 4517 m_argCount = 11; 4518 m_unit = CSSParser::FNumber; 4519 } else if (equalIgnoringCase(name, "matrix3d(")) { 4520 m_type = WebKitCSSTransformValue::Matrix3DTransformOperation; 4521 m_argCount = 31; 4522 m_unit = CSSParser::FNumber; 4523 } else if (equalIgnoringCase(name, "perspective(")) { 4524 m_type = WebKitCSSTransformValue::PerspectiveTransformOperation; 4525 m_unit = CSSParser::FNumber; 4526 } 4527 4528 if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "translate(")) { 4529 m_allowSingleArgument = true; 4530 m_argCount = 3; 4531 } 4532 } 4533 4534 WebKitCSSTransformValue::TransformOperationType type() const { return m_type; } 4535 unsigned argCount() const { return m_argCount; } 4536 CSSParser::Units unit() const { return m_unit; } 4537 4538 bool unknown() const { return m_type == WebKitCSSTransformValue::UnknownTransformOperation; } 4539 bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); } 4540 4541private: 4542 WebKitCSSTransformValue::TransformOperationType m_type; 4543 unsigned m_argCount; 4544 bool m_allowSingleArgument; 4545 CSSParser::Units m_unit; 4546}; 4547 4548PassRefPtr<CSSValueList> CSSParser::parseTransform() 4549{ 4550 if (!m_valueList) 4551 return 0; 4552 4553 // The transform is a list of functional primitives that specify transform operations. 4554 // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation. 4555 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); 4556 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { 4557 if (value->unit != CSSParserValue::Function || !value->function) 4558 return 0; 4559 4560 // Every primitive requires at least one argument. 4561 CSSParserValueList* args = value->function->args; 4562 if (!args) 4563 return 0; 4564 4565 // See if the specified primitive is one we understand. 4566 TransformOperationInfo info(value->function->name); 4567 if (info.unknown()) 4568 return 0; 4569 4570 if (!info.hasCorrectArgCount(args->size())) 4571 return 0; 4572 4573 // Create the new WebKitCSSTransformValue for this operation and add it to our list. 4574 RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(info.type()); 4575 list->append(transformValue); 4576 4577 // Snag our values. 4578 CSSParserValue* a = args->current(); 4579 unsigned argNumber = 0; 4580 while (a) { 4581 CSSParser::Units unit = info.unit(); 4582 4583 // 4th param of rotate3d() is an angle rather than a bare number, validate it as such 4584 if (info.type() == WebKitCSSTransformValue::Rotate3DTransformOperation && argNumber == 3) { 4585 if (!validUnit(a, FAngle, true)) 4586 return 0; 4587 } else if (!validUnit(a, unit, true)) 4588 return 0; 4589 4590 // Add the value to the current transform operation. 4591 transformValue->append(CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit)); 4592 4593 a = args->next(); 4594 if (!a) 4595 break; 4596 if (a->unit != CSSParserValue::Operator || a->iValue != ',') 4597 return 0; 4598 a = args->next(); 4599 4600 argNumber++; 4601 } 4602 } 4603 4604 return list.release(); 4605} 4606 4607bool CSSParser::parseTransformOrigin(int propId, int& propId1, int& propId2, int& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3) 4608{ 4609 propId1 = propId; 4610 propId2 = propId; 4611 propId3 = propId; 4612 if (propId == CSSPropertyWebkitTransformOrigin) { 4613 propId1 = CSSPropertyWebkitTransformOriginX; 4614 propId2 = CSSPropertyWebkitTransformOriginY; 4615 propId3 = CSSPropertyWebkitTransformOriginZ; 4616 } 4617 4618 switch (propId) { 4619 case CSSPropertyWebkitTransformOrigin: 4620 parseTransformOriginShorthand(value, value2, value3); 4621 // parseTransformOriginShorthand advances the m_valueList pointer 4622 break; 4623 case CSSPropertyWebkitTransformOriginX: { 4624 bool xFound = false, yFound = true; 4625 value = parseFillPositionXY(xFound, yFound); 4626 if (value) 4627 m_valueList->next(); 4628 break; 4629 } 4630 case CSSPropertyWebkitTransformOriginY: { 4631 bool xFound = true, yFound = false; 4632 value = parseFillPositionXY(xFound, yFound); 4633 if (value) 4634 m_valueList->next(); 4635 break; 4636 } 4637 case CSSPropertyWebkitTransformOriginZ: { 4638 if (validUnit(m_valueList->current(), FLength, m_strict)) 4639 value = CSSPrimitiveValue::create(m_valueList->current()->fValue, (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit); 4640 if (value) 4641 m_valueList->next(); 4642 break; 4643 } 4644 } 4645 4646 return value; 4647} 4648 4649bool CSSParser::parsePerspectiveOrigin(int propId, int& propId1, int& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2) 4650{ 4651 propId1 = propId; 4652 propId2 = propId; 4653 if (propId == CSSPropertyWebkitPerspectiveOrigin) { 4654 propId1 = CSSPropertyWebkitPerspectiveOriginX; 4655 propId2 = CSSPropertyWebkitPerspectiveOriginY; 4656 } 4657 4658 switch (propId) { 4659 case CSSPropertyWebkitPerspectiveOrigin: 4660 parseFillPosition(value, value2); 4661 break; 4662 case CSSPropertyWebkitPerspectiveOriginX: { 4663 bool xFound = false, yFound = true; 4664 value = parseFillPositionXY(xFound, yFound); 4665 if (value) 4666 m_valueList->next(); 4667 break; 4668 } 4669 case CSSPropertyWebkitPerspectiveOriginY: { 4670 bool xFound = true, yFound = false; 4671 value = parseFillPositionXY(xFound, yFound); 4672 if (value) 4673 m_valueList->next(); 4674 break; 4675 } 4676 } 4677 4678 return value; 4679} 4680 4681static inline int yyerror(const char*) { return 1; } 4682 4683#define END_TOKEN 0 4684 4685#include "CSSGrammar.h" 4686 4687int CSSParser::lex(void* yylvalWithoutType) 4688{ 4689 YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType); 4690 int length; 4691 4692 lex(); 4693 4694 UChar* t = text(&length); 4695 4696 switch (token()) { 4697 case WHITESPACE: 4698 case SGML_CD: 4699 case INCLUDES: 4700 case DASHMATCH: 4701 break; 4702 4703 case URI: 4704 case STRING: 4705 case IDENT: 4706 case NTH: 4707 case HEX: 4708 case IDSEL: 4709 case DIMEN: 4710 case UNICODERANGE: 4711 case FUNCTION: 4712 case NOTFUNCTION: 4713 case VARCALL: 4714 yylval->string.characters = t; 4715 yylval->string.length = length; 4716 break; 4717 4718 case IMPORT_SYM: 4719 case PAGE_SYM: 4720 case MEDIA_SYM: 4721 case FONT_FACE_SYM: 4722 case CHARSET_SYM: 4723 case NAMESPACE_SYM: 4724 case WEBKIT_KEYFRAMES_SYM: 4725 4726 case IMPORTANT_SYM: 4727 break; 4728 4729 case QEMS: 4730 length--; 4731 case GRADS: 4732 case TURNS: 4733 length--; 4734 case DEGS: 4735 case RADS: 4736 case KHERZ: 4737 case REMS: 4738 length--; 4739 case MSECS: 4740 case HERZ: 4741 case EMS: 4742 case EXS: 4743 case PXS: 4744 case CMS: 4745 case MMS: 4746 case INS: 4747 case PTS: 4748 case PCS: 4749 length--; 4750 case SECS: 4751 case PERCENTAGE: 4752 length--; 4753 case FLOATTOKEN: 4754 case INTEGER: 4755 yylval->number = charactersToDouble(t, length); 4756 break; 4757 4758 default: 4759 break; 4760 } 4761 4762 return token(); 4763} 4764 4765static inline bool isCSSWhitespace(UChar c) 4766{ 4767 return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f'; 4768} 4769 4770void CSSParser::recheckAtKeyword(const UChar* str, int len) 4771{ 4772 String ruleName(str, len); 4773 if (equalIgnoringCase(ruleName, "@import")) 4774 yyTok = IMPORT_SYM; 4775 else if (equalIgnoringCase(ruleName, "@page")) 4776 yyTok = PAGE_SYM; 4777 else if (equalIgnoringCase(ruleName, "@media")) 4778 yyTok = MEDIA_SYM; 4779 else if (equalIgnoringCase(ruleName, "@font-face")) 4780 yyTok = FONT_FACE_SYM; 4781 else if (equalIgnoringCase(ruleName, "@charset")) 4782 yyTok = CHARSET_SYM; 4783 else if (equalIgnoringCase(ruleName, "@namespace")) 4784 yyTok = NAMESPACE_SYM; 4785 else if (equalIgnoringCase(ruleName, "@-webkit-keyframes")) 4786 yyTok = WEBKIT_KEYFRAMES_SYM; 4787 else if (equalIgnoringCase(ruleName, "@-webkit-mediaquery")) 4788 yyTok = WEBKIT_MEDIAQUERY_SYM; 4789 // FIXME: Add CSS Variables if we ever decide to turn it back on. 4790} 4791 4792UChar* CSSParser::text(int *length) 4793{ 4794 UChar* start = yytext; 4795 int l = yyleng; 4796 switch (yyTok) { 4797 case STRING: 4798 l--; 4799 /* nobreak */ 4800 case HEX: 4801 case IDSEL: 4802 start++; 4803 l--; 4804 break; 4805 case URI: 4806 // "url("{w}{string}{w}")" 4807 // "url("{w}{url}{w}")" 4808 // strip "url(" and ")" 4809 start += 4; 4810 l -= 5; 4811 // strip {w} 4812 while (l && isCSSWhitespace(*start)) { 4813 ++start; 4814 --l; 4815 } 4816 while (l && isCSSWhitespace(start[l - 1])) 4817 --l; 4818 if (l && (*start == '"' || *start == '\'')) { 4819 ASSERT(l >= 2 && start[l - 1] == *start); 4820 ++start; 4821 l -= 2; 4822 } 4823 break; 4824 case VARCALL: 4825 // "-webkit-var("{w}{ident}{w}")" 4826 // strip "-webkit-var(" and ")" 4827 start += 12; 4828 l -= 13; 4829 // strip {w} 4830 while (l && isCSSWhitespace(*start)) { 4831 ++start; 4832 --l; 4833 } 4834 while (l && isCSSWhitespace(start[l - 1])) 4835 --l; 4836 break; 4837 default: 4838 break; 4839 } 4840 4841 // process escapes 4842 UChar* out = start; 4843 UChar* escape = 0; 4844 4845 bool sawEscape = false; 4846 4847 for (int i = 0; i < l; i++) { 4848 UChar* current = start + i; 4849 if (escape == current - 1) { 4850 if (isASCIIHexDigit(*current)) 4851 continue; 4852 if (yyTok == STRING && 4853 (*current == '\n' || *current == '\r' || *current == '\f')) { 4854 // ### handle \r\n case 4855 if (*current != '\r') 4856 escape = 0; 4857 continue; 4858 } 4859 // in all other cases copy the char to output 4860 // ### 4861 *out++ = *current; 4862 escape = 0; 4863 continue; 4864 } 4865 if (escape == current - 2 && yyTok == STRING && 4866 *(current-1) == '\r' && *current == '\n') { 4867 escape = 0; 4868 continue; 4869 } 4870 if (escape > current - 7 && isASCIIHexDigit(*current)) 4871 continue; 4872 if (escape) { 4873 // add escaped char 4874 unsigned uc = 0; 4875 escape++; 4876 while (escape < current) { 4877 uc *= 16; 4878 uc += toASCIIHexValue(*escape); 4879 escape++; 4880 } 4881 // can't handle chars outside ucs2 4882 if (uc > 0xffff) 4883 uc = 0xfffd; 4884 *out++ = uc; 4885 escape = 0; 4886 if (isCSSWhitespace(*current)) 4887 continue; 4888 } 4889 if (!escape && *current == '\\') { 4890 escape = current; 4891 sawEscape = true; 4892 continue; 4893 } 4894 *out++ = *current; 4895 } 4896 if (escape) { 4897 // add escaped char 4898 unsigned uc = 0; 4899 escape++; 4900 while (escape < start+l) { 4901 uc *= 16; 4902 uc += toASCIIHexValue(*escape); 4903 escape++; 4904 } 4905 // can't handle chars outside ucs2 4906 if (uc > 0xffff) 4907 uc = 0xfffd; 4908 *out++ = uc; 4909 } 4910 4911 *length = out - start; 4912 4913 // If we have an unrecognized @-keyword, and if we handled any escapes at all, then 4914 // we should attempt to adjust yyTok to the correct type. 4915 if (yyTok == ATKEYWORD && sawEscape) 4916 recheckAtKeyword(start, *length); 4917 4918 return start; 4919} 4920 4921CSSSelector* CSSParser::createFloatingSelector() 4922{ 4923 CSSSelector* selector = fastNew<CSSSelector>(); 4924 m_floatingSelectors.add(selector); 4925 return selector; 4926} 4927 4928CSSSelector* CSSParser::sinkFloatingSelector(CSSSelector* selector) 4929{ 4930 if (selector) { 4931 ASSERT(m_floatingSelectors.contains(selector)); 4932 m_floatingSelectors.remove(selector); 4933 } 4934 return selector; 4935} 4936 4937CSSParserValueList* CSSParser::createFloatingValueList() 4938{ 4939 CSSParserValueList* list = new CSSParserValueList; 4940 m_floatingValueLists.add(list); 4941 return list; 4942} 4943 4944CSSParserValueList* CSSParser::sinkFloatingValueList(CSSParserValueList* list) 4945{ 4946 if (list) { 4947 ASSERT(m_floatingValueLists.contains(list)); 4948 m_floatingValueLists.remove(list); 4949 } 4950 return list; 4951} 4952 4953CSSParserFunction* CSSParser::createFloatingFunction() 4954{ 4955 CSSParserFunction* function = new CSSParserFunction; 4956 m_floatingFunctions.add(function); 4957 return function; 4958} 4959 4960CSSParserFunction* CSSParser::sinkFloatingFunction(CSSParserFunction* function) 4961{ 4962 if (function) { 4963 ASSERT(m_floatingFunctions.contains(function)); 4964 m_floatingFunctions.remove(function); 4965 } 4966 return function; 4967} 4968 4969CSSParserValue& CSSParser::sinkFloatingValue(CSSParserValue& value) 4970{ 4971 if (value.unit == CSSParserValue::Function) { 4972 ASSERT(m_floatingFunctions.contains(value.function)); 4973 m_floatingFunctions.remove(value.function); 4974 } 4975 return value; 4976} 4977 4978MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values) 4979{ 4980 delete m_floatingMediaQueryExp; 4981 m_floatingMediaQueryExp = new MediaQueryExp(mediaFeature, values); 4982 return m_floatingMediaQueryExp; 4983} 4984 4985MediaQueryExp* CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* e) 4986{ 4987 ASSERT(e == m_floatingMediaQueryExp); 4988 m_floatingMediaQueryExp = 0; 4989 return e; 4990} 4991 4992Vector<MediaQueryExp*>* CSSParser::createFloatingMediaQueryExpList() 4993{ 4994 if (m_floatingMediaQueryExpList) { 4995 deleteAllValues(*m_floatingMediaQueryExpList); 4996 delete m_floatingMediaQueryExpList; 4997 } 4998 m_floatingMediaQueryExpList = new Vector<MediaQueryExp*>; 4999 return m_floatingMediaQueryExpList; 5000} 5001 5002Vector<MediaQueryExp*>* CSSParser::sinkFloatingMediaQueryExpList(Vector<MediaQueryExp*>* l) 5003{ 5004 ASSERT(l == m_floatingMediaQueryExpList); 5005 m_floatingMediaQueryExpList = 0; 5006 return l; 5007} 5008 5009MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor r, const String& mediaType, Vector<MediaQueryExp*>* exprs) 5010{ 5011 delete m_floatingMediaQuery; 5012 m_floatingMediaQuery = new MediaQuery(r, mediaType, exprs); 5013 return m_floatingMediaQuery; 5014} 5015 5016MediaQuery* CSSParser::createFloatingMediaQuery(Vector<MediaQueryExp*>* exprs) 5017{ 5018 return createFloatingMediaQuery(MediaQuery::None, "all", exprs); 5019} 5020 5021MediaQuery* CSSParser::sinkFloatingMediaQuery(MediaQuery* mq) 5022{ 5023 ASSERT(mq == m_floatingMediaQuery); 5024 m_floatingMediaQuery = 0; 5025 return mq; 5026} 5027 5028MediaList* CSSParser::createMediaList() 5029{ 5030 RefPtr<MediaList> list = MediaList::create(); 5031 MediaList* result = list.get(); 5032 m_parsedStyleObjects.append(list.release()); 5033 return result; 5034} 5035 5036CSSRule* CSSParser::createCharsetRule(const CSSParserString& charset) 5037{ 5038 if (!m_styleSheet) 5039 return 0; 5040 RefPtr<CSSCharsetRule> rule = CSSCharsetRule::create(m_styleSheet, charset); 5041 CSSCharsetRule* result = rule.get(); 5042 m_parsedStyleObjects.append(rule.release()); 5043 return result; 5044} 5045 5046CSSRule* CSSParser::createImportRule(const CSSParserString& url, MediaList* media) 5047{ 5048 if (!media || !m_styleSheet || !m_allowImportRules) 5049 return 0; 5050 RefPtr<CSSImportRule> rule = CSSImportRule::create(m_styleSheet, url, media); 5051 CSSImportRule* result = rule.get(); 5052 m_parsedStyleObjects.append(rule.release()); 5053 return result; 5054} 5055 5056CSSRule* CSSParser::createMediaRule(MediaList* media, CSSRuleList* rules) 5057{ 5058 if (!media || !rules || !m_styleSheet) 5059 return 0; 5060 m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false; 5061 RefPtr<CSSMediaRule> rule = CSSMediaRule::create(m_styleSheet, media, rules); 5062 CSSMediaRule* result = rule.get(); 5063 m_parsedStyleObjects.append(rule.release()); 5064 return result; 5065} 5066 5067CSSRuleList* CSSParser::createRuleList() 5068{ 5069 RefPtr<CSSRuleList> list = CSSRuleList::create(); 5070 CSSRuleList* listPtr = list.get(); 5071 5072 m_parsedRuleLists.append(list.release()); 5073 return listPtr; 5074} 5075 5076WebKitCSSKeyframesRule* CSSParser::createKeyframesRule() 5077{ 5078 m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false; 5079 RefPtr<WebKitCSSKeyframesRule> rule = WebKitCSSKeyframesRule::create(m_styleSheet); 5080 WebKitCSSKeyframesRule* rulePtr = rule.get(); 5081 m_parsedStyleObjects.append(rule.release()); 5082 return rulePtr; 5083} 5084 5085CSSRule* CSSParser::createStyleRule(Vector<CSSSelector*>* selectors) 5086{ 5087 m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false; 5088 CSSStyleRule* result = 0; 5089 if (selectors) { 5090 RefPtr<CSSStyleRule> rule = CSSStyleRule::create(m_styleSheet); 5091 rule->adoptSelectorVector(*selectors); 5092 if (m_hasFontFaceOnlyValues) 5093 deleteFontFaceOnlyValues(); 5094 rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties)); 5095 result = rule.get(); 5096 m_parsedStyleObjects.append(rule.release()); 5097 } 5098 clearProperties(); 5099 return result; 5100} 5101 5102CSSRule* CSSParser::createFontFaceRule() 5103{ 5104 m_allowImportRules = m_allowNamespaceDeclarations = m_allowVariablesRules = false; 5105 RefPtr<CSSFontFaceRule> rule = CSSFontFaceRule::create(m_styleSheet); 5106 for (unsigned i = 0; i < m_numParsedProperties; ++i) { 5107 CSSProperty* property = m_parsedProperties[i]; 5108 int id = property->id(); 5109 if ((id == CSSPropertyFontWeight || id == CSSPropertyFontStyle || id == CSSPropertyFontVariant) && property->value()->isPrimitiveValue()) { 5110 RefPtr<CSSValue> value = property->m_value.release(); 5111 property->m_value = CSSValueList::createCommaSeparated(); 5112 static_cast<CSSValueList*>(property->m_value.get())->append(value.release()); 5113 } 5114 } 5115 rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties)); 5116 clearProperties(); 5117 CSSFontFaceRule* result = rule.get(); 5118 m_parsedStyleObjects.append(rule.release()); 5119 return result; 5120} 5121 5122void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri) 5123{ 5124 if (!m_styleSheet || !m_allowNamespaceDeclarations) 5125 return; 5126 m_allowImportRules = false; 5127 m_allowVariablesRules = false; 5128 m_styleSheet->addNamespace(this, prefix, uri); 5129} 5130 5131#if !ENABLE(CSS_VARIABLES) 5132 5133CSSRule* CSSParser::createVariablesRule(MediaList*, bool) 5134{ 5135 return 0; 5136} 5137 5138bool CSSParser::addVariable(const CSSParserString&, CSSParserValueList*) 5139{ 5140 return false; 5141} 5142 5143bool CSSParser::addVariableDeclarationBlock(const CSSParserString&) 5144{ 5145 return false; 5146} 5147 5148#else 5149 5150CSSRule* CSSParser::createVariablesRule(MediaList* mediaList, bool variablesKeyword) 5151{ 5152 if (!m_allowVariablesRules) 5153 return 0; 5154 m_allowImportRules = false; 5155 RefPtr<CSSVariablesRule> rule = CSSVariablesRule::create(m_styleSheet, mediaList, variablesKeyword); 5156 rule->setDeclaration(CSSVariablesDeclaration::create(rule.get(), m_variableNames, m_variableValues)); 5157 clearVariables(); 5158 CSSRule* result = rule.get(); 5159 m_parsedStyleObjects.append(rule.release()); 5160 return result; 5161} 5162 5163bool CSSParser::addVariable(const CSSParserString& name, CSSParserValueList* valueList) 5164{ 5165 if (checkForVariables(valueList)) { 5166 delete valueList; 5167 return false; 5168 } 5169 m_variableNames.append(String(name)); 5170 m_variableValues.append(CSSValueList::createFromParserValueList(valueList)); 5171 return true; 5172} 5173 5174bool CSSParser::addVariableDeclarationBlock(const CSSParserString&) 5175{ 5176// FIXME: Disabling declarations as variable values for now since they no longer have a common base class with CSSValues. 5177#if 0 5178 m_variableNames.append(String(name)); 5179 m_variableValues.append(CSSMutableStyleDeclaration::create(0, m_parsedProperties, m_numParsedProperties)); 5180 clearProperties(); 5181#endif 5182 return true; 5183} 5184 5185#endif 5186 5187void CSSParser::clearVariables() 5188{ 5189 m_variableNames.clear(); 5190 m_variableValues.clear(); 5191} 5192 5193bool CSSParser::parseVariable(CSSVariablesDeclaration* declaration, const String& variableName, const String& variableValue) 5194{ 5195#ifdef ANDROID_INSTRUMENT 5196 android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); 5197#endif 5198 m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet()); 5199 5200 String nameValuePair = variableName + ": "; 5201 nameValuePair += variableValue; 5202 5203 setupParser("@-webkit-variables-decls{", nameValuePair, "} "); 5204 cssyyparse(this); 5205 m_rule = 0; 5206 5207 bool ok = false; 5208 if (m_variableNames.size()) { 5209 ok = true; 5210 declaration->addParsedVariable(variableName, m_variableValues[0]); 5211 } 5212 5213 clearVariables(); 5214 5215#ifdef ANDROID_INSTRUMENT 5216 android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); 5217#endif 5218 return ok; 5219} 5220 5221void CSSParser::parsePropertyWithResolvedVariables(int propId, bool isImportant, CSSMutableStyleDeclaration* declaration, CSSParserValueList* list) 5222{ 5223 m_valueList = list; 5224 m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet()); 5225 5226 if (parseValue(propId, isImportant)) 5227 declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties); 5228 5229 clearProperties(); 5230 m_valueList = 0; 5231} 5232 5233bool CSSParser::checkForVariables(CSSParserValueList* valueList) 5234{ 5235 if (!valueList || !valueList->containsVariables()) 5236 return false; 5237 5238 bool hasVariables = false; 5239 for (unsigned i = 0; i < valueList->size(); ++i) { 5240 if (valueList->valueAt(i)->isVariable()) { 5241 hasVariables = true; 5242 break; 5243 } 5244 5245 if (valueList->valueAt(i)->unit == CSSParserValue::Function && checkForVariables(valueList->valueAt(i)->function->args)) { 5246 hasVariables = true; 5247 break; 5248 } 5249 } 5250 5251 return hasVariables; 5252} 5253 5254void CSSParser::addUnresolvedProperty(int propId, bool important) 5255{ 5256 RefPtr<CSSVariableDependentValue> val = CSSVariableDependentValue::create(CSSValueList::createFromParserValueList(m_valueList)); 5257 addProperty(propId, val.release(), important); 5258} 5259 5260void CSSParser::deleteFontFaceOnlyValues() 5261{ 5262 ASSERT(m_hasFontFaceOnlyValues); 5263 int deletedProperties = 0; 5264 5265 for (unsigned i = 0; i < m_numParsedProperties; ++i) { 5266 CSSProperty* property = m_parsedProperties[i]; 5267 int id = property->id(); 5268 if ((id == CSSPropertyFontWeight || id == CSSPropertyFontStyle || id == CSSPropertyFontVariant) && property->value()->isValueList()) { 5269 delete property; 5270 deletedProperties++; 5271 } else if (deletedProperties) 5272 m_parsedProperties[i - deletedProperties] = m_parsedProperties[i]; 5273 } 5274 5275 m_numParsedProperties -= deletedProperties; 5276} 5277 5278WebKitCSSKeyframeRule* CSSParser::createKeyframeRule(CSSParserValueList* keys) 5279{ 5280 // Create a key string from the passed keys 5281 String keyString; 5282 for (unsigned i = 0; i < keys->size(); ++i) { 5283 float key = (float) keys->valueAt(i)->fValue; 5284 if (i != 0) 5285 keyString += ","; 5286 keyString += String::number(key); 5287 keyString += "%"; 5288 } 5289 5290 RefPtr<WebKitCSSKeyframeRule> keyframe = WebKitCSSKeyframeRule::create(m_styleSheet); 5291 keyframe->setKeyText(keyString); 5292 keyframe->setDeclaration(CSSMutableStyleDeclaration::create(0, m_parsedProperties, m_numParsedProperties)); 5293 5294 clearProperties(); 5295 5296 WebKitCSSKeyframeRule* keyframePtr = keyframe.get(); 5297 m_parsedStyleObjects.append(keyframe.release()); 5298 return keyframePtr; 5299} 5300 5301void CSSParser::invalidBlockHit() 5302{ 5303 if (m_styleSheet && !m_hadSyntacticallyValidCSSRule) 5304 m_styleSheet->setHasSyntacticallyValidCSSHeader(false); 5305} 5306 5307static int cssPropertyID(const UChar* propertyName, unsigned length) 5308{ 5309 if (!length) 5310 return 0; 5311 if (length > maxCSSPropertyNameLength) 5312 return 0; 5313 5314 char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character 5315 5316 for (unsigned i = 0; i != length; ++i) { 5317 UChar c = propertyName[i]; 5318 if (c == 0 || c >= 0x7F) 5319 return 0; // illegal character 5320 buffer[i] = toASCIILower(c); 5321 } 5322 buffer[length] = '\0'; 5323 5324 const char* name = buffer; 5325 if (buffer[0] == '-') { 5326 // If the prefix is -apple- or -khtml-, change it to -webkit-. 5327 // This makes the string one character longer. 5328 if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) { 5329 memmove(buffer + 7, buffer + 6, length + 1 - 6); 5330 memcpy(buffer, "-webkit", 7); 5331 ++length; 5332 } 5333 5334 if (hasPrefix(buffer, length, "-webkit")) { 5335 if (strcmp(buffer, "-webkit-opacity") == 0) { 5336 // Honor -webkit-opacity as a synonym for opacity. 5337 // This was the only syntax that worked in Safari 1.1, and may be in use on some websites and widgets. 5338 const char* const opacity = "opacity"; 5339 name = opacity; 5340 length = strlen(opacity); 5341 } else if (hasPrefix(buffer + 7, length - 7, "-border-")) { 5342 // -webkit-border-*-*-radius worked in Safari 4 and earlier. -webkit-border-radius syntax 5343 // differs from border-radius, so it is remains as a distinct property. 5344 if (!strcmp(buffer + 15, "top-left-radius") 5345 || !strcmp(buffer + 15, "top-right-radius") 5346 || !strcmp(buffer + 15, "bottom-right-radius") 5347 || !strcmp(buffer + 15, "bottom-left-radius")) { 5348 name = buffer + 8; 5349 length -= 8; 5350 } 5351 } 5352 } 5353 } 5354 5355 const props* hashTableEntry = findProp(name, length); 5356 return hashTableEntry ? hashTableEntry->id : 0; 5357} 5358 5359int cssPropertyID(const String& string) 5360{ 5361 return cssPropertyID(string.characters(), string.length()); 5362} 5363 5364int cssPropertyID(const CSSParserString& string) 5365{ 5366 return cssPropertyID(string.characters, string.length); 5367} 5368 5369int cssValueKeywordID(const CSSParserString& string) 5370{ 5371 unsigned length = string.length; 5372 if (!length) 5373 return 0; 5374 if (length > maxCSSValueKeywordLength) 5375 return 0; 5376 5377 char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character 5378 5379 for (unsigned i = 0; i != length; ++i) { 5380 UChar c = string.characters[i]; 5381 if (c == 0 || c >= 0x7F) 5382 return 0; // illegal character 5383 buffer[i] = WTF::toASCIILower(c); 5384 } 5385 buffer[length] = '\0'; 5386 5387 if (buffer[0] == '-') { 5388 // If the prefix is -apple- or -khtml-, change it to -webkit-. 5389 // This makes the string one character longer. 5390 if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) { 5391 memmove(buffer + 7, buffer + 6, length + 1 - 6); 5392 memcpy(buffer, "-webkit", 7); 5393 ++length; 5394 } 5395 } 5396 5397 const css_value* hashTableEntry = findValue(buffer, length); 5398 return hashTableEntry ? hashTableEntry->id : 0; 5399} 5400 5401#define YY_DECL int CSSParser::lex() 5402#define yyconst const 5403typedef int yy_state_type; 5404typedef unsigned YY_CHAR; 5405// The following line makes sure we treat non-Latin-1 Unicode characters correctly. 5406#define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c) 5407#define YY_DO_BEFORE_ACTION \ 5408 yytext = yy_bp; \ 5409 yyleng = (int) (yy_cp - yy_bp); \ 5410 yy_hold_char = *yy_cp; \ 5411 *yy_cp = 0; \ 5412 yy_c_buf_p = yy_cp; 5413#define YY_BREAK break; 5414#define ECHO 5415#define YY_RULE_SETUP 5416#define INITIAL 0 5417#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) 5418#define yyterminate() yyTok = END_TOKEN; return yyTok 5419#define YY_FATAL_ERROR(a) 5420// The following line is needed to build the tokenizer with a condition stack. 5421// The macro is used in the tokenizer grammar with lines containing 5422// BEGIN(mediaqueries) and BEGIN(initial). yy_start acts as index to 5423// tokenizer transition table, and 'mediaqueries' and 'initial' are 5424// offset multipliers that specify which transitions are active 5425// in the tokenizer during in each condition (tokenizer state). 5426#define BEGIN yy_start = 1 + 2 * 5427 5428#include "tokenizer.cpp" 5429 5430} 5431