/WebCore/css/CSSParser.cpp

http://github.com/CyanogenMod/android_external_webkit · C++ · 1670 lines · 1411 code · 149 blank · 110 comment · 673 complexity · 777351b62f087173c71955797a2ed02b MD5 · raw file

  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. #include "config.h"
  25. #include "CSSParser.h"
  26. #include "CString.h"
  27. #include "CSSTimingFunctionValue.h"
  28. #include "CSSBorderImageValue.h"
  29. #include "CSSCanvasValue.h"
  30. #include "CSSCharsetRule.h"
  31. #include "CSSCursorImageValue.h"
  32. #include "CSSHelper.h"
  33. #include "CSSImageValue.h"
  34. #include "CSSFontFaceRule.h"
  35. #include "CSSFontFaceSrcValue.h"
  36. #include "CSSGradientValue.h"
  37. #include "CSSImportRule.h"
  38. #include "CSSInheritedValue.h"
  39. #include "CSSInitialValue.h"
  40. #include "CSSMediaRule.h"
  41. #include "CSSMutableStyleDeclaration.h"
  42. #include "CSSPrimitiveValue.h"
  43. #include "CSSProperty.h"
  44. #include "CSSPropertyNames.h"
  45. #include "CSSQuirkPrimitiveValue.h"
  46. #include "CSSReflectValue.h"
  47. #include "CSSRuleList.h"
  48. #include "CSSSelector.h"
  49. #include "CSSStyleRule.h"
  50. #include "CSSStyleSheet.h"
  51. #include "CSSUnicodeRangeValue.h"
  52. #include "CSSValueKeywords.h"
  53. #include "CSSValueList.h"
  54. #include "CSSVariableDependentValue.h"
  55. #include "CSSVariablesDeclaration.h"
  56. #include "CSSVariablesRule.h"
  57. #include "Counter.h"
  58. #include "Document.h"
  59. #include "FloatConversion.h"
  60. #include "FontFamilyValue.h"
  61. #include "FontValue.h"
  62. #include "MediaList.h"
  63. #include "MediaQueryExp.h"
  64. #include "Pair.h"
  65. #include "Rect.h"
  66. #include "ShadowValue.h"
  67. #include "WebKitCSSKeyframeRule.h"
  68. #include "WebKitCSSKeyframesRule.h"
  69. #include "WebKitCSSTransformValue.h"
  70. #include <wtf/dtoa.h>
  71. #if ENABLE(DASHBOARD_SUPPORT)
  72. #include "DashboardRegion.h"
  73. #endif
  74. #define YYDEBUG 0
  75. #if YYDEBUG > 0
  76. extern int cssyydebug;
  77. #endif
  78. extern int cssyyparse(void* parser);
  79. using namespace std;
  80. using namespace WTF;
  81. #include "CSSPropertyNames.cpp"
  82. #include "CSSValueKeywords.c"
  83. #ifdef ANDROID_INSTRUMENT
  84. #include "TimeCounter.h"
  85. #endif
  86. namespace WebCore {
  87. static bool equal(const CSSParserString& a, const char* b)
  88. {
  89. for (int i = 0; i < a.length; ++i) {
  90. if (!b[i])
  91. return false;
  92. if (a.characters[i] != b[i])
  93. return false;
  94. }
  95. return !b[a.length];
  96. }
  97. static bool equalIgnoringCase(const CSSParserString& a, const char* b)
  98. {
  99. for (int i = 0; i < a.length; ++i) {
  100. if (!b[i])
  101. return false;
  102. ASSERT(!isASCIIUpper(b[i]));
  103. if (toASCIILower(a.characters[i]) != b[i])
  104. return false;
  105. }
  106. return !b[a.length];
  107. }
  108. static bool hasPrefix(const char* string, unsigned length, const char* prefix)
  109. {
  110. for (unsigned i = 0; i < length; ++i) {
  111. if (!prefix[i])
  112. return true;
  113. if (string[i] != prefix[i])
  114. return false;
  115. }
  116. return false;
  117. }
  118. CSSParser::CSSParser(bool strictParsing)
  119. : m_strict(strictParsing)
  120. , m_important(false)
  121. , m_id(0)
  122. , m_styleSheet(0)
  123. , m_mediaQuery(0)
  124. , m_valueList(0)
  125. , m_parsedProperties(static_cast<CSSProperty**>(fastMalloc(32 * sizeof(CSSProperty*))))
  126. , m_numParsedProperties(0)
  127. , m_maxParsedProperties(32)
  128. , m_inParseShorthand(0)
  129. , m_currentShorthand(0)
  130. , m_implicitShorthand(false)
  131. , m_hasFontFaceOnlyValues(false)
  132. , m_hadSyntacticallyValidCSSRule(false)
  133. , m_defaultNamespace(starAtom)
  134. , m_data(0)
  135. , yy_start(1)
  136. , m_allowImportRules(true)
  137. , m_allowVariablesRules(true)
  138. , m_allowNamespaceDeclarations(true)
  139. , m_floatingMediaQuery(0)
  140. , m_floatingMediaQueryExp(0)
  141. , m_floatingMediaQueryExpList(0)
  142. {
  143. #if YYDEBUG > 0
  144. cssyydebug = 1;
  145. #endif
  146. }
  147. CSSParser::~CSSParser()
  148. {
  149. clearProperties();
  150. fastFree(m_parsedProperties);
  151. clearVariables();
  152. delete m_valueList;
  153. fastFree(m_data);
  154. if (m_floatingMediaQueryExpList) {
  155. deleteAllValues(*m_floatingMediaQueryExpList);
  156. delete m_floatingMediaQueryExpList;
  157. }
  158. delete m_floatingMediaQueryExp;
  159. delete m_floatingMediaQuery;
  160. fastDeleteAllValues(m_floatingSelectors);
  161. deleteAllValues(m_floatingValueLists);
  162. deleteAllValues(m_floatingFunctions);
  163. deleteAllValues(m_reusableSelectorVector);
  164. }
  165. void CSSParserString::lower()
  166. {
  167. // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
  168. // that can potentially change the length of the string rather than the character
  169. // by character kind. If we don't need Unicode lowercasing, it would be good to
  170. // simplify this function.
  171. if (charactersAreAllASCII(characters, length)) {
  172. // Fast case for all-ASCII.
  173. for (int i = 0; i < length; i++)
  174. characters[i] = toASCIILower(characters[i]);
  175. } else {
  176. for (int i = 0; i < length; i++)
  177. characters[i] = Unicode::toLower(characters[i]);
  178. }
  179. }
  180. void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix)
  181. {
  182. int length = string.length() + strlen(prefix) + strlen(suffix) + 2;
  183. fastFree(m_data);
  184. m_data = static_cast<UChar*>(fastMalloc(length * sizeof(UChar)));
  185. for (unsigned i = 0; i < strlen(prefix); i++)
  186. m_data[i] = prefix[i];
  187. memcpy(m_data + strlen(prefix), string.characters(), string.length() * sizeof(UChar));
  188. unsigned start = strlen(prefix) + string.length();
  189. unsigned end = start + strlen(suffix);
  190. for (unsigned i = start; i < end; i++)
  191. m_data[i] = suffix[i - start];
  192. m_data[length - 1] = 0;
  193. m_data[length - 2] = 0;
  194. yy_hold_char = 0;
  195. yyleng = 0;
  196. yytext = yy_c_buf_p = m_data;
  197. yy_hold_char = *yy_c_buf_p;
  198. }
  199. void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string)
  200. {
  201. #ifdef ANDROID_INSTRUMENT
  202. android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
  203. #endif
  204. m_styleSheet = sheet;
  205. m_defaultNamespace = starAtom; // Reset the default namespace.
  206. setupParser("", string, "");
  207. cssyyparse(this);
  208. m_rule = 0;
  209. #ifdef ANDROID_INSTRUMENT
  210. android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
  211. #endif
  212. }
  213. PassRefPtr<CSSRule> CSSParser::parseRule(CSSStyleSheet* sheet, const String& string)
  214. {
  215. #ifdef ANDROID_INSTRUMENT
  216. android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
  217. #endif
  218. m_styleSheet = sheet;
  219. m_allowNamespaceDeclarations = false;
  220. setupParser("@-webkit-rule{", string, "} ");
  221. cssyyparse(this);
  222. #ifdef ANDROID_INSTRUMENT
  223. android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
  224. #endif
  225. return m_rule.release();
  226. }
  227. PassRefPtr<CSSRule> CSSParser::parseKeyframeRule(CSSStyleSheet *sheet, const String &string)
  228. {
  229. #ifdef ANDROID_INSTRUMENT
  230. android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
  231. #endif
  232. m_styleSheet = sheet;
  233. setupParser("@-webkit-keyframe-rule{ ", string, "} ");
  234. cssyyparse(this);
  235. #ifdef ANDROID_INSTRUMENT
  236. android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
  237. #endif
  238. return m_keyframe.release();
  239. }
  240. bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int id, const String& string, bool important)
  241. {
  242. #ifdef ANDROID_INSTRUMENT
  243. android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
  244. #endif
  245. ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
  246. m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
  247. setupParser("@-webkit-value{", string, "} ");
  248. m_id = id;
  249. m_important = important;
  250. cssyyparse(this);
  251. m_rule = 0;
  252. bool ok = false;
  253. if (m_hasFontFaceOnlyValues)
  254. deleteFontFaceOnlyValues();
  255. if (m_numParsedProperties) {
  256. ok = true;
  257. declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
  258. clearProperties();
  259. }
  260. #ifdef ANDROID_INSTRUMENT
  261. android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
  262. #endif
  263. return ok;
  264. }
  265. // color will only be changed when string contains a valid css color, making it
  266. // possible to set up a default color.
  267. bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
  268. {
  269. color = 0;
  270. CSSParser parser(true);
  271. // First try creating a color specified by name or the "#" syntax.
  272. if (!parser.parseColor(string, color, strict)) {
  273. RefPtr<CSSMutableStyleDeclaration> dummyStyleDeclaration = CSSMutableStyleDeclaration::create();
  274. // Now try to create a color from the rgb() or rgba() syntax.
  275. if (parser.parseColor(dummyStyleDeclaration.get(), string)) {
  276. CSSValue* value = parser.m_parsedProperties[0]->value();
  277. if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) {
  278. CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
  279. color = primitiveValue->getRGBA32Value();
  280. }
  281. } else
  282. return false;
  283. }
  284. return true;
  285. }
  286. bool CSSParser::parseColor(CSSMutableStyleDeclaration* declaration, const String& string)
  287. {
  288. #ifdef ANDROID_INSTRUMENT
  289. android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
  290. #endif
  291. ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
  292. m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
  293. setupParser("@-webkit-decls{color:", string, "} ");
  294. cssyyparse(this);
  295. m_rule = 0;
  296. #ifdef ANDROID_INSTRUMENT
  297. android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
  298. #endif
  299. return (m_numParsedProperties && m_parsedProperties[0]->m_id == CSSPropertyColor);
  300. }
  301. void CSSParser::parseSelector(const String& string, Document* doc, CSSSelectorList& selectorList)
  302. {
  303. #ifdef ANDROID_INSTRUMENT
  304. android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
  305. #endif
  306. RefPtr<CSSStyleSheet> dummyStyleSheet = CSSStyleSheet::create(doc);
  307. m_styleSheet = dummyStyleSheet.get();
  308. m_selectorListForParseSelector = &selectorList;
  309. setupParser("@-webkit-selector{", string, "}");
  310. cssyyparse(this);
  311. m_selectorListForParseSelector = 0;
  312. #ifdef ANDROID_INSTRUMENT
  313. android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
  314. #endif
  315. }
  316. bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration* declaration, const String& string)
  317. {
  318. #ifdef ANDROID_INSTRUMENT
  319. android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
  320. #endif
  321. ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
  322. m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
  323. setupParser("@-webkit-decls{", string, "} ");
  324. cssyyparse(this);
  325. m_rule = 0;
  326. bool ok = false;
  327. if (m_hasFontFaceOnlyValues)
  328. deleteFontFaceOnlyValues();
  329. if (m_numParsedProperties) {
  330. ok = true;
  331. declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
  332. clearProperties();
  333. }
  334. #ifdef ANDROID_INSTRUMENT
  335. android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
  336. #endif
  337. return ok;
  338. }
  339. bool CSSParser::parseMediaQuery(MediaList* queries, const String& string)
  340. {
  341. if (string.isEmpty())
  342. return true;
  343. #ifdef ANDROID_INSTRUMENT
  344. android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter);
  345. #endif
  346. m_mediaQuery = 0;
  347. // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
  348. // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
  349. setupParser("@-webkit-mediaquery ", string, "} ");
  350. cssyyparse(this);
  351. bool ok = false;
  352. if (m_mediaQuery) {
  353. ok = true;
  354. queries->appendMediaQuery(m_mediaQuery);
  355. m_mediaQuery = 0;
  356. }
  357. #ifdef ANDROID_INSTRUMENT
  358. android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__);
  359. #endif
  360. return ok;
  361. }
  362. void CSSParser::addProperty(int propId, PassRefPtr<CSSValue> value, bool important)
  363. {
  364. auto_ptr<CSSProperty> prop(new CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand));
  365. if (m_numParsedProperties >= m_maxParsedProperties) {
  366. m_maxParsedProperties += 32;
  367. if (m_maxParsedProperties > UINT_MAX / sizeof(CSSProperty*))
  368. return;
  369. m_parsedProperties = static_cast<CSSProperty**>(fastRealloc(m_parsedProperties,
  370. m_maxParsedProperties * sizeof(CSSProperty*)));
  371. }
  372. m_parsedProperties[m_numParsedProperties++] = prop.release();
  373. }
  374. void CSSParser::rollbackLastProperties(int num)
  375. {
  376. ASSERT(num >= 0);
  377. ASSERT(m_numParsedProperties >= static_cast<unsigned>(num));
  378. for (int i = 0; i < num; ++i)
  379. delete m_parsedProperties[--m_numParsedProperties];
  380. }
  381. void CSSParser::clearProperties()
  382. {
  383. for (unsigned i = 0; i < m_numParsedProperties; i++)
  384. delete m_parsedProperties[i];
  385. m_numParsedProperties = 0;
  386. m_hasFontFaceOnlyValues = false;
  387. }
  388. Document* CSSParser::document() const
  389. {
  390. StyleBase* root = m_styleSheet;
  391. Document* doc = 0;
  392. while (root && root->parent())
  393. root = root->parent();
  394. if (root && root->isCSSStyleSheet())
  395. doc = static_cast<CSSStyleSheet*>(root)->doc();
  396. return doc;
  397. }
  398. bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, bool strict)
  399. {
  400. bool b = false;
  401. switch (value->unit) {
  402. case CSSPrimitiveValue::CSS_NUMBER:
  403. b = (unitflags & FNumber);
  404. if (!b && ((unitflags & (FLength | FAngle | FTime)) && (value->fValue == 0 || !strict))) {
  405. value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
  406. ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
  407. b = true;
  408. }
  409. if (!b && (unitflags & FInteger) && value->isInt)
  410. b = true;
  411. break;
  412. case CSSPrimitiveValue::CSS_PERCENTAGE:
  413. b = (unitflags & FPercent);
  414. break;
  415. case CSSParserValue::Q_EMS:
  416. case CSSPrimitiveValue::CSS_EMS:
  417. case CSSPrimitiveValue::CSS_REMS:
  418. case CSSPrimitiveValue::CSS_EXS:
  419. case CSSPrimitiveValue::CSS_PX:
  420. case CSSPrimitiveValue::CSS_CM:
  421. case CSSPrimitiveValue::CSS_MM:
  422. case CSSPrimitiveValue::CSS_IN:
  423. case CSSPrimitiveValue::CSS_PT:
  424. case CSSPrimitiveValue::CSS_PC:
  425. b = (unitflags & FLength);
  426. break;
  427. case CSSPrimitiveValue::CSS_MS:
  428. case CSSPrimitiveValue::CSS_S:
  429. b = (unitflags & FTime);
  430. break;
  431. case CSSPrimitiveValue::CSS_DEG:
  432. case CSSPrimitiveValue::CSS_RAD:
  433. case CSSPrimitiveValue::CSS_GRAD:
  434. case CSSPrimitiveValue::CSS_TURN:
  435. b = (unitflags & FAngle);
  436. break;
  437. case CSSPrimitiveValue::CSS_HZ:
  438. case CSSPrimitiveValue::CSS_KHZ:
  439. case CSSPrimitiveValue::CSS_DIMENSION:
  440. default:
  441. break;
  442. }
  443. if (b && unitflags & FNonNeg && value->fValue < 0)
  444. b = false;
  445. return b;
  446. }
  447. static int unitFromString(CSSParserValue* value)
  448. {
  449. if (value->unit != CSSPrimitiveValue::CSS_IDENT || value->id)
  450. return 0;
  451. if (equal(value->string, "em"))
  452. return CSSPrimitiveValue::CSS_EMS;
  453. if (equal(value->string, "rem"))
  454. return CSSPrimitiveValue::CSS_REMS;
  455. if (equal(value->string, "ex"))
  456. return CSSPrimitiveValue::CSS_EXS;
  457. if (equal(value->string, "px"))
  458. return CSSPrimitiveValue::CSS_PX;
  459. if (equal(value->string, "cm"))
  460. return CSSPrimitiveValue::CSS_CM;
  461. if (equal(value->string, "mm"))
  462. return CSSPrimitiveValue::CSS_MM;
  463. if (equal(value->string, "in"))
  464. return CSSPrimitiveValue::CSS_IN;
  465. if (equal(value->string, "pt"))
  466. return CSSPrimitiveValue::CSS_PT;
  467. if (equal(value->string, "pc"))
  468. return CSSPrimitiveValue::CSS_PC;
  469. if (equal(value->string, "deg"))
  470. return CSSPrimitiveValue::CSS_DEG;
  471. if (equal(value->string, "rad"))
  472. return CSSPrimitiveValue::CSS_RAD;
  473. if (equal(value->string, "grad"))
  474. return CSSPrimitiveValue::CSS_GRAD;
  475. if (equal(value->string, "turn"))
  476. return CSSPrimitiveValue::CSS_TURN;
  477. if (equal(value->string, "ms"))
  478. return CSSPrimitiveValue::CSS_MS;
  479. if (equal(value->string, "s"))
  480. return CSSPrimitiveValue::CSS_S;
  481. if (equal(value->string, "Hz"))
  482. return CSSPrimitiveValue::CSS_HZ;
  483. if (equal(value->string, "kHz"))
  484. return CSSPrimitiveValue::CSS_KHZ;
  485. return 0;
  486. }
  487. void CSSParser::checkForOrphanedUnits()
  488. {
  489. if (m_strict || inShorthand())
  490. return;
  491. // The purpose of this code is to implement the WinIE quirk that allows unit types to be separated from their numeric values
  492. // 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.
  493. CSSParserValue* numericVal = 0;
  494. unsigned size = m_valueList->size();
  495. for (unsigned i = 0; i < size; i++) {
  496. CSSParserValue* value = m_valueList->valueAt(i);
  497. if (numericVal) {
  498. // Change the unit type of the numeric val to match.
  499. int unit = unitFromString(value);
  500. if (unit) {
  501. numericVal->unit = unit;
  502. numericVal = 0;
  503. // Now delete the bogus unit value.
  504. m_valueList->deleteValueAt(i);
  505. 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).
  506. size--;
  507. continue;
  508. }
  509. }
  510. numericVal = (value->unit == CSSPrimitiveValue::CSS_NUMBER) ? value : 0;
  511. }
  512. }
  513. bool CSSParser::parseValue(int propId, bool important)
  514. {
  515. if (!m_valueList)
  516. return false;
  517. CSSParserValue *value = m_valueList->current();
  518. if (!value)
  519. return false;
  520. int id = value->id;
  521. // In quirks mode, we will look for units that have been incorrectly separated from the number they belong to
  522. // by a space. We go ahead and associate the unit with the number even though it is invalid CSS.
  523. checkForOrphanedUnits();
  524. int num = inShorthand() ? 1 : m_valueList->size();
  525. if (id == CSSValueInherit) {
  526. if (num != 1)
  527. return false;
  528. addProperty(propId, CSSInheritedValue::create(), important);
  529. return true;
  530. }
  531. else if (id == CSSValueInitial) {
  532. if (num != 1)
  533. return false;
  534. addProperty(propId, CSSInitialValue::createExplicit(), important);
  535. return true;
  536. }
  537. // If we have any variables, then we don't parse the list of values yet. We add them to the declaration
  538. // as unresolved, and allow them to be parsed later. The parse is considered "successful" for now, even though
  539. // it might ultimately fail once the variable has been resolved.
  540. if (!inShorthand() && checkForVariables(m_valueList)) {
  541. addUnresolvedProperty(propId, important);
  542. return true;
  543. }
  544. bool validPrimitive = false;
  545. RefPtr<CSSValue> parsedValue;
  546. switch (static_cast<CSSPropertyID>(propId)) {
  547. /* The comment to the left defines all valid value of this properties as defined
  548. * in CSS 2, Appendix F. Property index
  549. */
  550. /* All the CSS properties are not supported by the renderer at the moment.
  551. * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
  552. * (see parseAuralValues). As we don't support them at all this seems reasonable.
  553. */
  554. case CSSPropertySize: // <length>{1,2} | auto | portrait | landscape | inherit
  555. case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit
  556. if (id)
  557. validPrimitive = true;
  558. break;
  559. case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | inherit
  560. if (id == CSSValueNormal ||
  561. id == CSSValueEmbed ||
  562. id == CSSValueBidiOverride)
  563. validPrimitive = true;
  564. break;
  565. case CSSPropertyPosition: // static | relative | absolute | fixed | inherit
  566. if (id == CSSValueStatic ||
  567. id == CSSValueRelative ||
  568. id == CSSValueAbsolute ||
  569. id == CSSValueFixed)
  570. validPrimitive = true;
  571. break;
  572. case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit
  573. case CSSPropertyPageBreakBefore:
  574. case CSSPropertyWebkitColumnBreakAfter:
  575. case CSSPropertyWebkitColumnBreakBefore:
  576. if (id == CSSValueAuto ||
  577. id == CSSValueAlways ||
  578. id == CSSValueAvoid ||
  579. id == CSSValueLeft ||
  580. id == CSSValueRight)
  581. validPrimitive = true;
  582. break;
  583. case CSSPropertyPageBreakInside: // avoid | auto | inherit
  584. case CSSPropertyWebkitColumnBreakInside:
  585. if (id == CSSValueAuto || id == CSSValueAvoid)
  586. validPrimitive = true;
  587. break;
  588. case CSSPropertyEmptyCells: // show | hide | inherit
  589. if (id == CSSValueShow ||
  590. id == CSSValueHide)
  591. validPrimitive = true;
  592. break;
  593. case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
  594. // close-quote | no-open-quote | no-close-quote ]+ | inherit
  595. return parseContent(propId, important);
  596. case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit
  597. if (id == CSSValueNormal ||
  598. id == CSSValuePre ||
  599. id == CSSValuePreWrap ||
  600. id == CSSValuePreLine ||
  601. id == CSSValueNowrap)
  602. validPrimitive = true;
  603. break;
  604. case CSSPropertyClip: // <shape> | auto | inherit
  605. if (id == CSSValueAuto)
  606. validPrimitive = true;
  607. else if (value->unit == CSSParserValue::Function)
  608. return parseShape(propId, important);
  609. break;
  610. /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
  611. * correctly and allows optimization in WebCore::applyRule(..)
  612. */
  613. case CSSPropertyCaptionSide: // top | bottom | left | right | inherit
  614. if (id == CSSValueLeft || id == CSSValueRight ||
  615. id == CSSValueTop || id == CSSValueBottom)
  616. validPrimitive = true;
  617. break;
  618. case CSSPropertyBorderCollapse: // collapse | separate | inherit
  619. if (id == CSSValueCollapse || id == CSSValueSeparate)
  620. validPrimitive = true;
  621. break;
  622. case CSSPropertyVisibility: // visible | hidden | collapse | inherit
  623. if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueCollapse)
  624. validPrimitive = true;
  625. break;
  626. case CSSPropertyOverflow: {
  627. ShorthandScope scope(this, propId);
  628. if (num != 1 || !parseValue(CSSPropertyOverflowX, important))
  629. return false;
  630. CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value();
  631. addProperty(CSSPropertyOverflowY, value, important);
  632. return true;
  633. }
  634. case CSSPropertyOverflowX:
  635. case CSSPropertyOverflowY: // visible | hidden | scroll | auto | marquee | overlay | inherit
  636. if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueScroll || id == CSSValueAuto ||
  637. id == CSSValueOverlay || id == CSSValueWebkitMarquee)
  638. validPrimitive = true;
  639. break;
  640. case CSSPropertyListStylePosition: // inside | outside | inherit
  641. if (id == CSSValueInside || id == CSSValueOutside)
  642. validPrimitive = true;
  643. break;
  644. case CSSPropertyListStyleType:
  645. // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
  646. // for the list of supported list-style-types.
  647. if ((id >= CSSValueDisc && id <= CSSValueKatakanaIroha) || id == CSSValueNone)
  648. validPrimitive = true;
  649. break;
  650. case CSSPropertyDisplay:
  651. // inline | block | list-item | run-in | inline-block | table |
  652. // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
  653. // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit
  654. #if ENABLE(WCSS)
  655. if ((id >= CSSValueInline && id <= CSSValueWapMarquee) || id == CSSValueNone)
  656. #else
  657. if ((id >= CSSValueInline && id <= CSSValueWebkitInlineBox) || id == CSSValueNone)
  658. #endif
  659. validPrimitive = true;
  660. break;
  661. case CSSPropertyDirection: // ltr | rtl | inherit
  662. if (id == CSSValueLtr || id == CSSValueRtl)
  663. validPrimitive = true;
  664. break;
  665. case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit
  666. if ((id >= CSSValueCapitalize && id <= CSSValueLowercase) || id == CSSValueNone)
  667. validPrimitive = true;
  668. break;
  669. case CSSPropertyFloat: // left | right | none | inherit + center for buggy CSS
  670. if (id == CSSValueLeft || id == CSSValueRight ||
  671. id == CSSValueNone || id == CSSValueCenter)
  672. validPrimitive = true;
  673. break;
  674. case CSSPropertyClear: // none | left | right | both | inherit
  675. if (id == CSSValueNone || id == CSSValueLeft ||
  676. id == CSSValueRight|| id == CSSValueBoth)
  677. validPrimitive = true;
  678. break;
  679. case CSSPropertyTextAlign:
  680. // left | right | center | justify | webkit_left | webkit_right | webkit_center | start | end | <string> | inherit
  681. if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitCenter) || id == CSSValueStart || id == CSSValueEnd ||
  682. value->unit == CSSPrimitiveValue::CSS_STRING)
  683. validPrimitive = true;
  684. break;
  685. case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit
  686. if (id == CSSValueAuto || id == CSSValueNone || (id >= CSSValueInset && id <= CSSValueDouble))
  687. validPrimitive = true;
  688. break;
  689. case CSSPropertyBorderTopStyle: //// <border-style> | inherit
  690. case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
  691. case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
  692. case CSSPropertyBorderLeftStyle:
  693. case CSSPropertyWebkitColumnRuleStyle:
  694. if (id >= CSSValueNone && id <= CSSValueDouble)
  695. validPrimitive = true;
  696. break;
  697. case CSSPropertyFontWeight: // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
  698. return parseFontWeight(important);
  699. case CSSPropertyBorderSpacing: {
  700. const int properties[2] = { CSSPropertyWebkitBorderHorizontalSpacing,
  701. CSSPropertyWebkitBorderVerticalSpacing };
  702. if (num == 1) {
  703. ShorthandScope scope(this, CSSPropertyBorderSpacing);
  704. if (!parseValue(properties[0], important))
  705. return false;
  706. CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value();
  707. addProperty(properties[1], value, important);
  708. return true;
  709. }
  710. else if (num == 2) {
  711. ShorthandScope scope(this, CSSPropertyBorderSpacing);
  712. if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
  713. return false;
  714. return true;
  715. }
  716. return false;
  717. }
  718. case CSSPropertyWebkitBorderHorizontalSpacing:
  719. case CSSPropertyWebkitBorderVerticalSpacing:
  720. validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
  721. break;
  722. case CSSPropertyOutlineColor: // <color> | invert | inherit
  723. // Outline color has "invert" as additional keyword.
  724. // Also, we want to allow the special focus color even in strict parsing mode.
  725. if (propId == CSSPropertyOutlineColor && (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor)) {
  726. validPrimitive = true;
  727. break;
  728. }
  729. /* nobreak */
  730. case CSSPropertyBackgroundColor: // <color> | inherit
  731. case CSSPropertyBorderTopColor: // <color> | inherit
  732. case CSSPropertyBorderRightColor: // <color> | inherit
  733. case CSSPropertyBorderBottomColor: // <color> | inherit
  734. case CSSPropertyBorderLeftColor: // <color> | inherit
  735. case CSSPropertyColor: // <color> | inherit
  736. case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors
  737. case CSSPropertyTextUnderlineColor:
  738. case CSSPropertyTextOverlineColor:
  739. case CSSPropertyWebkitColumnRuleColor:
  740. case CSSPropertyWebkitTextFillColor:
  741. case CSSPropertyWebkitTextStrokeColor:
  742. if (id == CSSValueWebkitText)
  743. validPrimitive = true; // Always allow this, even when strict parsing is on,
  744. // since we use this in our UA sheets.
  745. else if (id == CSSValueCurrentcolor)
  746. validPrimitive = true;
  747. else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu ||
  748. (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && !m_strict)) {
  749. validPrimitive = true;
  750. } else {
  751. parsedValue = parseColor();
  752. if (parsedValue)
  753. m_valueList->next();
  754. }
  755. break;
  756. case CSSPropertyCursor: {
  757. // [<uri>,]* [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
  758. // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
  759. // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
  760. // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
  761. // -webkit-zoom-in | -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
  762. RefPtr<CSSValueList> list;
  763. while (value && value->unit == CSSPrimitiveValue::CSS_URI) {
  764. if (!list)
  765. list = CSSValueList::createCommaSeparated();
  766. String uri = value->string;
  767. Vector<int> coords;
  768. value = m_valueList->next();
  769. while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
  770. coords.append(int(value->fValue));
  771. value = m_valueList->next();
  772. }
  773. IntPoint hotspot;
  774. int nrcoords = coords.size();
  775. if (nrcoords > 0 && nrcoords != 2)
  776. return false;
  777. if (nrcoords == 2)
  778. hotspot = IntPoint(coords[0], coords[1]);
  779. if (!uri.isNull() && m_styleSheet) {
  780. // FIXME: The completeURL call should be done when using the CSSCursorImageValue,
  781. // not when creating it.
  782. list->append(CSSCursorImageValue::create(m_styleSheet->completeURL(uri), hotspot));
  783. }
  784. if ((m_strict && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ',')))
  785. return false;
  786. value = m_valueList->next(); // comma
  787. }
  788. if (list) {
  789. if (!value) { // no value after url list (MSIE 5 compatibility)
  790. if (list->length() != 1)
  791. return false;
  792. } else if (!m_strict && value->id == CSSValueHand) // MSIE 5 compatibility :/
  793. list->append(CSSPrimitiveValue::createIdentifier(CSSValuePointer));
  794. else if (value && ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone))
  795. list->append(CSSPrimitiveValue::createIdentifier(value->id));
  796. m_valueList->next();
  797. parsedValue = list.release();
  798. break;
  799. }
  800. id = value->id;
  801. if (!m_strict && value->id == CSSValueHand) { // MSIE 5 compatibility :/
  802. id = CSSValuePointer;
  803. validPrimitive = true;
  804. } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
  805. validPrimitive = true;
  806. break;
  807. }
  808. case CSSPropertyBackgroundAttachment:
  809. case CSSPropertyBackgroundClip:
  810. case CSSPropertyWebkitBackgroundClip:
  811. case CSSPropertyWebkitBackgroundComposite:
  812. case CSSPropertyBackgroundImage:
  813. case CSSPropertyBackgroundOrigin:
  814. case CSSPropertyWebkitBackgroundOrigin:
  815. case CSSPropertyBackgroundPosition:
  816. case CSSPropertyBackgroundPositionX:
  817. case CSSPropertyBackgroundPositionY:
  818. case CSSPropertyBackgroundSize:
  819. case CSSPropertyWebkitBackgroundSize:
  820. case CSSPropertyBackgroundRepeat:
  821. case CSSPropertyBackgroundRepeatX:
  822. case CSSPropertyBackgroundRepeatY:
  823. case CSSPropertyWebkitMaskAttachment:
  824. case CSSPropertyWebkitMaskClip:
  825. case CSSPropertyWebkitMaskComposite:
  826. case CSSPropertyWebkitMaskImage:
  827. case CSSPropertyWebkitMaskOrigin:
  828. case CSSPropertyWebkitMaskPosition:
  829. case CSSPropertyWebkitMaskPositionX:
  830. case CSSPropertyWebkitMaskPositionY:
  831. case CSSPropertyWebkitMaskSize:
  832. case CSSPropertyWebkitMaskRepeat:
  833. case CSSPropertyWebkitMaskRepeatX:
  834. case CSSPropertyWebkitMaskRepeatY: {
  835. RefPtr<CSSValue> val1;
  836. RefPtr<CSSValue> val2;
  837. int propId1, propId2;
  838. bool result = false;
  839. if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
  840. OwnPtr<ShorthandScope> shorthandScope;
  841. if (propId == CSSPropertyBackgroundPosition ||
  842. propId == CSSPropertyBackgroundRepeat ||
  843. propId == CSSPropertyWebkitMaskPosition ||
  844. propId == CSSPropertyWebkitMaskRepeat) {
  845. shorthandScope.set(new ShorthandScope(this, propId));
  846. }
  847. addProperty(propId1, val1.release(), important);
  848. if (val2)
  849. addProperty(propId2, val2.release(), important);
  850. result = true;
  851. }
  852. m_implicitShorthand = false;
  853. return result;
  854. }
  855. case CSSPropertyListStyleImage: // <uri> | none | inherit
  856. if (id == CSSValueNone) {
  857. parsedValue = CSSImageValue::create();
  858. m_valueList->next();
  859. } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
  860. if (m_styleSheet) {
  861. // FIXME: The completeURL call should be done when using the CSSImageValue,
  862. // not when creating it.
  863. parsedValue = CSSImageValue::create(m_styleSheet->completeURL(value->string));
  864. m_valueList->next();
  865. }
  866. } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-gradient(")) {
  867. if (parseGradient(parsedValue))
  868. m_valueList->next();
  869. else
  870. return false;
  871. }
  872. break;
  873. case CSSPropertyWebkitTextStrokeWidth:
  874. case CSSPropertyOutlineWidth: // <border-width> | inherit
  875. case CSSPropertyBorderTopWidth: //// <border-width> | inherit
  876. case CSSPropertyBorderRightWidth: // Which is defined as
  877. case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
  878. case CSSPropertyBorderLeftWidth:
  879. case CSSPropertyWebkitColumnRuleWidth:
  880. if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
  881. validPrimitive = true;
  882. else
  883. validPrimitive = validUnit(value, FLength, m_strict);
  884. break;
  885. case CSSPropertyLetterSpacing: // normal | <length> | inherit
  886. case CSSPropertyWordSpacing: // normal | <length> | inherit
  887. if (id == CSSValueNormal)
  888. validPrimitive = true;
  889. else
  890. validPrimitive = validUnit(value, FLength, m_strict);
  891. break;
  892. case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
  893. if (id == CSSValueNormal || id == CSSValueBreakAll || id == CSSValueBreakWord)
  894. validPrimitive = true;
  895. break;
  896. case CSSPropertyWordWrap: // normal | break-word
  897. if (id == CSSValueNormal || id == CSSValueBreakWord)
  898. validPrimitive = true;
  899. break;
  900. case CSSPropertyTextIndent: // <length> | <percentage> | inherit
  901. case CSSPropertyPaddingTop: //// <padding-width> | inherit
  902. case CSSPropertyPaddingRight: // Which is defined as
  903. case CSSPropertyPaddingBottom: // <length> | <percentage>
  904. case CSSPropertyPaddingLeft: ////
  905. case CSSPropertyWebkitPaddingStart:
  906. validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
  907. break;
  908. case CSSPropertyMaxHeight: // <length> | <percentage> | none | inherit
  909. case CSSPropertyMaxWidth: // <length> | <percentage> | none | inherit
  910. if (id == CSSValueNone || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) {
  911. validPrimitive = true;
  912. break;
  913. }
  914. /* nobreak */
  915. case CSSPropertyMinHeight: // <length> | <percentage> | inherit
  916. case CSSPropertyMinWidth: // <length> | <percentage> | inherit
  917. if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
  918. validPrimitive = true;
  919. else
  920. validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
  921. break;
  922. case CSSPropertyFontSize:
  923. // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
  924. if (id >= CSSValueXxSmall && id <= CSSValueLarger)
  925. validPrimitive = true;
  926. else
  927. validPrimitive = (validUnit(value, FLength | FPercent | FNonNeg, m_strict));
  928. break;
  929. case CSSPropertyFontStyle: // normal | italic | oblique | inherit
  930. return parseFontStyle(important);
  931. case CSSPropertyFontVariant: // normal | small-caps | inherit
  932. return parseFontVariant(important);
  933. case CSSPropertyVerticalAlign:
  934. // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
  935. // <percentage> | <length> | inherit
  936. if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
  937. validPrimitive = true;
  938. else
  939. validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
  940. break;
  941. case CSSPropertyHeight: // <length> | <percentage> | auto | inherit
  942. case CSSPropertyWidth: // <length> | <percentage> | auto | inherit
  943. if (id == CSSValueAuto || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
  944. validPrimitive = true;
  945. else
  946. // ### handle multilength case where we allow relative units
  947. validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
  948. break;
  949. case CSSPropertyBottom: // <length> | <percentage> | auto | inherit
  950. case CSSPropertyLeft: // <length> | <percentage> | auto | inherit
  951. case CSSPropertyRight: // <length> | <percentage> | auto | inherit
  952. case CSSPropertyTop: // <length> | <percentage> | auto | inherit
  953. case CSSPropertyMarginTop: //// <margin-width> | inherit
  954. case CSSPropertyMarginRight: // Which is defined as
  955. case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit
  956. case CSSPropertyMarginLeft: ////
  957. case CSSPropertyWebkitMarginStart:
  958. if (id == CSSValueAuto)
  959. validPrimitive = true;
  960. else
  961. validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
  962. break;
  963. case CSSPropertyZIndex: // auto | <integer> | inherit
  964. if (id == CSSValueAuto) {
  965. validPrimitive = true;
  966. break;
  967. }
  968. /* nobreak */
  969. case CSSPropertyOrphans: // <integer> | inherit
  970. case CSSPropertyWidows: // <integer> | inherit
  971. // ### not supported later on
  972. validPrimitive = (!id && validUnit(value, FInteger, false));
  973. break;
  974. case CSSPropertyLineHeight: // normal | <number> | <length> | <percentage> | inherit
  975. if (id == CSSValueNormal)
  976. validPrimitive = true;
  977. else
  978. validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict));
  979. break;
  980. case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
  981. if (id != CSSValueNone)
  982. return parseCounter(propId, 1, important);
  983. validPrimitive = true;
  984. break;
  985. case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit
  986. if (id != CSSValueNone)
  987. return parseCounter(propId, 0, important);
  988. validPrimitive = true;
  989. break;
  990. case CSSPropertyFontFamily:
  991. // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
  992. {
  993. parsedValue = parseFontFamily();
  994. break;
  995. }
  996. case CSSPropertyTextDecoration:
  997. case CSSPropertyWebkitTextDecorationsInEffect:
  998. // none | [ underline || overline || line-through || blink ] | inherit
  999. if (id == CSSValueNone) {
  1000. validPrimitive = true;
  1001. } else {
  1002. RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
  1003. bool isValid = true;
  1004. while (isValid && value) {
  1005. switch (value->id) {
  1006. case CSSValueBlink:
  1007. break;
  1008. case CSSValueUnderline:
  1009. case CSSValueOverline:
  1010. case CSSValueLineThrough:
  1011. list->append(CSSPrimitiveValue::createIdentifier(value->id));
  1012. break;
  1013. default:
  1014. isValid = false;
  1015. }
  1016. value = m_valueList->next();
  1017. }
  1018. if (list->length() && isValid) {
  1019. parsedValue = list.release();
  1020. m_valueList->next();
  1021. }
  1022. }
  1023. break;
  1024. case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit
  1025. if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
  1026. validPrimitive = true;
  1027. else
  1028. validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, true));
  1029. break;
  1030. case CSSPropertyTableLayout: // auto | fixed | inherit
  1031. if (id == CSSValueAuto || id == CSSValueFixed)
  1032. validPrimitive = true;
  1033. break;
  1034. case CSSPropertySrc: // Only used within @font-face, so cannot use inherit | initial or be !important. This is a list of urls or local references.
  1035. return parseFontFaceSrc();
  1036. case CSSPropertyUnicodeRange:
  1037. return parseFontFaceUnicodeRange();
  1038. /* CSS3 properties */
  1039. case CSSPropertyWebkitAppearance:
  1040. if ((id >= CSSValueCheckbox && id <= CSSValueTextarea) || id == CSSValueNone)
  1041. validPrimitive = true;
  1042. break;
  1043. case CSSPropertyWebkitBinding:
  1044. #if ENABLE(XBL)
  1045. if (id == CSSValueNone)
  1046. validPrimitive = true;
  1047. else {
  1048. RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
  1049. CSSParserValue* val;
  1050. RefPtr<CSSValue> parsedValue;
  1051. while ((val = m_valueList->current())) {
  1052. if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
  1053. // FIXME: The completeURL call should be done when using the CSSPrimitiveValue,
  1054. // not when creating it.
  1055. parsedValue = CSSPrimitiveValue::create(m_styleSheet->completeURL(val->string), CSSPrimitiveValue::CSS_URI);
  1056. }
  1057. if (!parsedValue)
  1058. break;
  1059. // FIXME: We can't use release() here since we might hit this path twice
  1060. // but that logic seems wrong to me to begin with, we convert all non-uri values
  1061. // into the last seen URI value!?
  1062. // -webkit-binding: url(foo.xml), 1, 2; (if that were valid) is treated as:
  1063. // -webkit-binding: url(foo.xml), url(foo.xml), url(foo.xml); !?
  1064. values->append(parsedValue.get());
  1065. m_valueList->next();
  1066. }
  1067. if (!values->length())
  1068. return false;
  1069. addProperty(propId, values.release(), important);
  1070. m_valueList->next();
  1071. return true;
  1072. }
  1073. #endif
  1074. break;
  1075. case CSSPropertyWebkitBorderImage:
  1076. case CSSPropertyWebkitMaskBoxImage:
  1077. if (id == CSSValueNone)
  1078. validPrimitive = true;
  1079. else {
  1080. RefPtr<CSSValue> result;
  1081. if (parseBorderImage(propId, important, result)) {
  1082. addProperty(propId, result, important);
  1083. return true;
  1084. }
  1085. }
  1086. break;
  1087. case CSSPropertyBorderTopRightRadius:
  1088. case CSSPropertyBorderTopLeftRadius:
  1089. case CSSPropertyBorderBottomLeftRadius:
  1090. case CSSPropertyBorderBottomRightRadius: {
  1091. if (num != 1 && num != 2)
  1092. return false;
  1093. validPrimitive = validUnit(value, FLength, m_strict);
  1094. if (!validPrimitive)
  1095. return false;
  1096. RefPtr<CSSPrimitiveValue> parsedValue1 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
  1097. RefPtr<CSSPrimitiveValue> parsedValue2;
  1098. if (num == 2) {
  1099. value = m_valueList->next();
  1100. validPrimitive = validUnit(value, FLength, m_strict);
  1101. if (!validPrimitive)
  1102. return false;
  1103. parsedValue2 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
  1104. } else
  1105. parsedValue2 = parsedValue1;
  1106. RefPtr<Pair> pair = Pair::create(parsedValue1.release(), parsedValue2.release());
  1107. RefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(pair.release());
  1108. addProperty(propId, val.release(), important);
  1109. return true;
  1110. }
  1111. case CSSPropertyBorderRadius:
  1112. case CSSPropertyWebkitBorderRadius:
  1113. return parseBorderRadius(propId, important);
  1114. case CSSPropertyOutlineOffset:
  1115. validPrimitive = validUnit(value, FLength, m_strict);
  1116. break;
  1117. case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
  1118. case CSSPropertyWebkitBoxShadow:
  1119. if (id == CSSValueNone)
  1120. validPrimitive = true;
  1121. else
  1122. return parseShadow(propId, important);
  1123. break;
  1124. case CSSPropertyWebkitBoxReflect:
  1125. if (id == CSSValueNone)
  1126. validPrimitive = true;
  1127. else
  1128. return parseReflect(propId, important);
  1129. break;
  1130. case CSSPropertyOpacity:
  1131. validPrimitive = validUnit(value, FNumber, m_strict);
  1132. break;
  1133. case CSSPropertyWebkitBoxAlign:
  1134. if (id == CSSValueStretch || id == CSSValueStart || id == CSSValueEnd ||
  1135. id == CSSValueCenter || id == CSSValueBaseline)
  1136. validPrimitive = true;
  1137. break;
  1138. case CSSPropertyWebkitBoxDirection:
  1139. if (id == CSSValueNormal || id == CSSValueReverse)
  1140. validPrimitive = true;
  1141. break;
  1142. case CSSPropertyWebkitBoxLines:
  1143. if (id == CSSValueSingle || id == CSSValueMultiple)
  1144. validPrimitive = true;
  1145. break;
  1146. case CSSPropertyWebkitBoxOrient:
  1147. if (id == CSSValueHorizontal || id == CSSValueVertical ||
  1148. id == CSSValueInlineAxis || id == CSSValueBlockAxis)
  1149. validPrimitive = true;
  1150. break;
  1151. case CSSPropertyWebkitBoxPack:
  1152. if (id == CSSValueStart || id == CSSValueEnd ||
  1153. id == CSSValueCenter || id == CSSValueJustify)
  1154. validPrimitive = true;
  1155. break;
  1156. case CSSPropertyWebkitBoxFlex:
  1157. validPrimitive = validUnit(value, FNumber, m_strict);
  1158. break;
  1159. case CSSPropertyWebkitBoxFlexGroup:
  1160. case CSSPropertyWebkitBoxOrdinalGroup:
  1161. validPrimitive = validUnit(value, FInteger | FNonNeg, true);
  1162. break;
  1163. case CSSPropertyWebkitBoxSizing:
  1164. validPrimitive = id == CSSValueBorderBox || id == CSSValueContentBox;
  1165. break;
  1166. case CSSPropertyWebkitColorCorrection:
  1167. validPrimitive = id == CSSValueSrgb || id == CSSValueDefault;
  1168. break;
  1169. case CSSPropertyWebkitMarquee: {
  1170. const int properties[5] = { CSSPropertyWebkitMarqueeDirection, CSSPropertyWebkitMarqueeIncrement,
  1171. CSSPropertyWebkitMarqueeRepetition,
  1172. CSSPropertyWebkitMarqueeStyle, CSSPropertyWebkitMarqueeSpeed };
  1173. return parseShorthand(propId, properties, 5, important);
  1174. }
  1175. case CSSPropertyWebkitMarqueeDirection:
  1176. if (id == CSSValueForwards || id == CSSValueBackwards || id == CSSValueAhead ||
  1177. id == CSSValueReverse || id == CSSValueLeft || id == CSSValueRight || id == CSSValueDown ||
  1178. id == CSSValueUp || id == CSSValueAuto)
  1179. validPrimitive = true;
  1180. break;
  1181. case CSSPropertyWebkitMarqueeIncrement:
  1182. if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
  1183. validPrimitive = true;
  1184. else
  1185. validPrimitive = validUnit(value, FLength | FPercent, m_strict);
  1186. break;
  1187. case CSSPropertyWebkitMarqueeStyle:
  1188. if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate)
  1189. validPrimitive = true;
  1190. break;
  1191. case CSSPropertyWebkitMarqueeRepetition:
  1192. if (id == CSSValueInfinite)
  1193. validPrimitive = true;
  1194. else
  1195. validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict);
  1196. break;
  1197. case CSSPropertyWebkitMarqueeSpeed:
  1198. if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
  1199. validPrimitive = true;
  1200. else
  1201. validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict);
  1202. break;
  1203. #if ENABLE(WCSS)
  1204. case CSSPropertyWapMarqueeDir:
  1205. if (id == CSSValueLtr || id == CSSValueRtl)
  1206. validPrimitive = true;
  1207. break;
  1208. case CSSPropertyWapMarqueeStyle:
  1209. if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate)
  1210. validPrimitive = true;
  1211. break;
  1212. case CSSPropertyWapMarqueeLoop:
  1213. if (id == CSSValueInfinite)
  1214. validPrimitive = true;
  1215. else
  1216. validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict);
  1217. break;
  1218. case CSSPropertyWapMarqueeSpeed:
  1219. if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
  1220. validPrimitive = true;
  1221. else
  1222. validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict);
  1223. break;
  1224. #endif
  1225. case CSSPropertyWebkitUserDrag: // auto | none | element
  1226. if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueElement)
  1227. validPrimitive = true;
  1228. break;
  1229. case CSSPropertyWebkitUserModify: // read-only | read-write
  1230. if (id == CSSValueReadOnly || id == CSSValueReadWrite || id == CSSValueReadWritePlaintextOnly)
  1231. validPrimitive = true;
  1232. break;
  1233. case CSSPropertyWebkitUserSelect: // auto | none | text
  1234. if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueText)
  1235. validPrimitive = true;
  1236. break;
  1237. case CSSPropertyTextOverflow: // clip | ellipsis
  1238. if (id == CSSValueClip || id == CSSValueEllipsis)
  1239. validPrimitive = true;
  1240. break;
  1241. case CSSPropertyWebkitTransform:
  1242. if (id == CSSValueNone)
  1243. validPrimitive = true;
  1244. else {
  1245. PassRefPtr<CSSValue> val = parseTransform();
  1246. if (val) {
  1247. addProperty(propId, val, important);
  1248. return true;
  1249. }
  1250. return false;
  1251. }
  1252. break;
  1253. case CSSPropertyWebkitTransformOrigin:
  1254. case CSSPropertyWebkitTransformOriginX:
  1255. case CSSPropertyWebkitTransformOriginY:
  1256. case CSSPropertyWebkitTransformOriginZ: {
  1257. RefPtr<CSSValue> val1;
  1258. RefPtr<CSSValue> val2;
  1259. RefPtr<CSSValue> val3;
  1260. int propId1, propId2, propId3;
  1261. if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
  1262. addProperty(propId1, val1.release(), important);
  1263. if (val2)
  1264. addProperty(propId2, val2.release(), important);
  1265. if (val3)
  1266. addProperty(propId3, val3.release(), important);
  1267. return true;
  1268. }
  1269. return false;
  1270. }
  1271. case CSSPropertyWebkitTransformStyle:
  1272. if (value->id == CSSValueFlat || value->id == CSSValuePreserve3d)
  1273. validPrimitive = true;
  1274. break;
  1275. case CSSPropertyWebkitBackfaceVisibility:
  1276. if (value->id == CSSValueVisible || value->id == CSSValueHidden)
  1277. validPrimitive = true;
  1278. break;
  1279. case CSSPropertyWebkitPerspective:
  1280. if (id == CSSValueNone)
  1281. validPrimitive = true;
  1282. else {
  1283. // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
  1284. if (validUnit(value, FNumber | FLength | FNonNeg, m_strict)) {
  1285. RefPtr<CSSValue> val = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
  1286. if (val) {
  1287. addProperty(propId, val.release(), important);
  1288. return true;
  1289. }
  1290. return false;
  1291. }
  1292. }
  1293. break;
  1294. case CSSPropertyWebkitPerspectiveOrigin:
  1295. case CSSPropertyWebkitPerspectiveOriginX:
  1296. case CSSPropertyWebkitPerspectiveOriginY: {
  1297. RefPtr<CSSValue> val1;
  1298. RefPtr<CSSValue> val2;
  1299. int propId1, propId2;
  1300. if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
  1301. addProperty(propId1, val1.release(), important);
  1302. if (val2)
  1303. addProperty(propId2, val2.release(), important);
  1304. return true;
  1305. }
  1306. return false;
  1307. }
  1308. case CSSPropertyWebkitAnimationDelay:
  1309. case CSSPropertyWebkitAnimationDirection:
  1310. case CSSPropertyWebkitAnimationDuration:
  1311. case CSSPropertyWebkitAnimationName:
  1312. case CSSPropertyWebkitAnimationPlayState:
  1313. case CSSPropertyWebkitAnimationIterationCount:
  1314. case CSSPropertyWebkitAnimationTimingFunction:
  1315. case CSSPropertyWebkitTransitionDelay:
  1316. case CSSPropertyWebkitTransitionDuration:
  1317. case CSSPropertyWebkitTransitionTimingFunction:
  1318. case CSSPropertyWebkitTransitionProperty: {
  1319. RefPtr<CSSValue> val;
  1320. if (parseAnimationProperty(propId, val)) {
  1321. addProperty(propId, val.release(), important);
  1322. return true;
  1323. }
  1324. return false;
  1325. }
  1326. case CSSPropertyWebkitMarginCollapse: {
  1327. const int properties[2] = { CSSPropertyWebkitMarginTopCollapse,
  1328. CSSPropertyWebkitMarginBottomCollapse };
  1329. if (num == 1) {
  1330. ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
  1331. if (!parseValue(properties[0], important))
  1332. return false;
  1333. CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value();
  1334. addProperty(properties[1], value, important);
  1335. return true;
  1336. }
  1337. else if (num == 2) {
  1338. ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
  1339. if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
  1340. return false;
  1341. return true;
  1342. }
  1343. return false;
  1344. }
  1345. case CSSPropertyWebkitMarginTopCollapse:
  1346. case CSSPropertyWebkitMarginBottomCollapse:
  1347. if (id == CSSValueCollapse || id == CSSValueSeparate || id == CSSValueDiscard)
  1348. validPrimitive = true;
  1349. break;
  1350. case CSSPropertyTextLineThroughMode:
  1351. case CSSPropertyTextOverlineMode:
  1352. case CSSPropertyTextUnderlineMode:
  1353. if (id == CSSValueContinuous || id == CSSValueSkipWhiteSpace)
  1354. validPrimitive = true;
  1355. break;
  1356. case CSSPropertyTextLineThroughStyle:
  1357. case CSSPropertyTextOverlineStyle:
  1358. case CSSPropertyTextUnderlineStyle:
  1359. if (id == CSSValueNone || id == CSSValueSolid || id == CSSValueDouble ||
  1360. id == CSSValueDashed || id == CSSValueDotDash || id == CSSValueDotDotDash ||
  1361. id == CSSValueWave)
  1362. validPrimitive = true;
  1363. break;
  1364. case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
  1365. if (id == CSSValueAuto || id == CSSValueOptimizespeed || id == CSSValueOptimizelegibility
  1366. || id == CSSValueGeometricprecision)
  1367. validPrimitive = true;
  1368. break;
  1369. case CSSPropertyTextLineThroughWidth:
  1370. case CSSPropertyTextOverlineWidth:
  1371. case CSSPropertyTextUnderlineWidth:
  1372. if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
  1373. id == CSSValueMedium || id == CSSValueThick)
  1374. validPrimitive = true;
  1375. else
  1376. validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent, m_strict);
  1377. break;
  1378. case CSSPropertyResize: // none | both | horizontal | vertical | auto
  1379. if (id == CSSValueNone || id == CSSValueBoth || id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
  1380. validPrimitive = true;
  1381. break;
  1382. case CSSPropertyWebkitColumnCount:
  1383. if (id == CSSValueAuto)
  1384. validPrimitive = true;
  1385. else
  1386. validPrimitive = !id && validUnit(value, FInteger | FNonNeg, false);
  1387. break;
  1388. case CSSPropertyWebkitColumnGap: // normal | <length>
  1389. if (id == CSSValueNormal)
  1390. validPrimitive = true;
  1391. else
  1392. validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
  1393. break;
  1394. case CSSPropertyWebkitColumnWidth: // auto | <length>
  1395. if (id == CSSValueAuto)
  1396. validPrimitive = true;
  1397. else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property.
  1398. validPrimitive = validUnit(value, FLength, true);
  1399. break;
  1400. case CSSPropertyPointerEvents:
  1401. // none | visiblePainted | visibleFill | visibleStroke | visible |
  1402. // painted | fill | stroke | auto | all | inherit
  1403. if (id == CSSValueVisible || id == CSSValueNone || id == CSSValueAll || id == CSSValueAuto ||
  1404. (id >= CSSValueVisiblepainted && id <= CSSValueStroke))
  1405. validPrimitive = true;
  1406. break;
  1407. // End of CSS3 properties
  1408. // Apple specific properties. These will never be standardized and are purely to
  1409. // support custom WebKit-based Apple applications.
  1410. case CSSPropertyWebkitLineClamp:
  1411. // When specifying number of lines, don't allow 0 as a valid value
  1412. // When specifying either type of unit, require non-negative integers
  1413. validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, false));
  1414. break;
  1415. case CSSPropertyWebkitTextSizeAdjust:
  1416. if (id == CSSValueAuto || id == CSSValueNone)
  1417. validPrimitive = true;
  1418. break;
  1419. case CSSPropertyWebkitRtlOrdering:
  1420. if (id == CSSValueLogical || id == CSSValueVisual)
  1421. validPrimitive = true;
  1422. break;
  1423. case CSSPropertyWebkitFontSizeDelta: // <length>
  1424. validPrimitive = validUnit(value, FLength, m_strict);
  1425. break;
  1426. case CSSPropertyWebkitNbspMode: // normal | space
  1427. if (id == CSSValueNormal || id == CSSValueSpace)
  1428. validPrimitive = true;
  1429. break;
  1430. case CSSPropertyWebkitLineBreak: // normal | after-white-space
  1431. if (id == CSSValueNormal || id == CSSValueAfterWhiteSpace)
  1432. validPrimitive = true;
  1433. break;
  1434. case CSSPropertyWebkitMatchNearestMailBlockquoteColor: // normal | match
  1435. if (id == CSSValueNormal || id == CSSValueMatch)
  1436. validPrimitive = true;
  1437. break;
  1438. case CSSPropertyWebkitHighlight:
  1439. if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
  1440. validPrimitive = true;
  1441. break;
  1442. case CSSPropertyWebkitBorderFit:
  1443. if (id == CSSValueBorder || id == CSSValueLines)
  1444. validPrimitive = true;
  1445. break;
  1446. case CSSPropertyWebkitTextSecurity:
  1447. // disc | circle | square | none | inherit
  1448. if (id == CSSValueDisc || id == CSSValueCircle || id == CSSValueSquare|| id == CSSValueNone)
  1449. validPrimitive = true;
  1450. break;
  1451. case CSSPropertyWebkitFontSmoothing:
  1452. if (id == CSSValueAuto || id == CSSValueNone
  1453. || id == CSSValueAntialiased || id == CSSValueSubpixelAntialiased)
  1454. validPrimitive = true;
  1455. break;
  1456. #if ENABLE(DASHBOARD_SUPPORT)
  1457. case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region>
  1458. if (value->unit == CSSParserValue::Function || id == CSSValueNone)
  1459. return parseDashboardRegions(propId, important);
  1460. break;
  1461. #endif
  1462. // End Apple-specific properties
  1463. /* shorthand properties */
  1464. case CSSPropertyBackground: {
  1465. // Position must come before color in this array because a plain old "0" is a legal color
  1466. // in quirks mode but it's usually the X coordinate of a position.
  1467. // FIXME: Add CSSPropertyBackgroundSize to the shorthand.
  1468. const int properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
  1469. CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
  1470. CSSPropertyBackgroundColor };
  1471. return parseFillShorthand(propId, properties, 6, important);
  1472. }
  1473. case CSSPropertyWebkitMask: {
  1474. const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
  1475. CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition,
  1476. CSSPropertyWebkitMaskOrigin };
  1477. return parseFillShorthand(propId, properties, 5, important);
  1478. }
  1479. case CSSPropertyBorder:
  1480. // [ 'border-width' || 'border-style' || <color> ] | inherit
  1481. {
  1482. const int properties[3] = { CSSPropertyBorderWidth, CSSPropertyBorderStyle,
  1483. CSSPropertyBorderColor };
  1484. return parseShorthand(propId, properties, 3, important);
  1485. }
  1486. case CSSPropertyBorderTop:
  1487. // [ 'border-top-width' || 'border-style' || <color> ] | inherit
  1488. {
  1489. const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle,
  1490. CSSPropertyBorderTopColor};
  1491. return parseShorthand(propId, properties, 3, important);
  1492. }
  1493. case CSSPropertyBorderRight:
  1494. // [ 'border-right-width' || 'border-style' || <color> ] | inherit
  1495. {
  1496. const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle,
  1497. CSSPropertyBorderRightColor };
  1498. return parseShorthand(propId, properties, 3, important);
  1499. }
  1500. case CSSPropertyBorderBottom:
  1501. // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
  1502. {
  1503. const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle,
  1504. CSSPropertyBorderBottomColor };
  1505. return parseShorthand(propId, properties, 3, important);
  1506. }
  1507. case CSSPropertyBorderLeft:
  1508. // [ 'border-left-width' || 'border-style' || <color> ] | inherit
  1509. {
  1510. const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle,
  1511. CSSPropertyBorderLeftColor };
  1512. return parseShorthand(propId, properties, 3, important);
  1513. }
  1514. case CSSPropertyOutline:
  1515. // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
  1516. {
  1517. const int properties[3] = { CSSPropertyOutlineWidth, CSSPropertyOutlineStyle,
  1518. CSSPropertyOutlineColor };
  1519. return parseShorthand(propId, properties, 3, important);
  1520. }
  1521. case CSSPropert