PageRenderTime 111ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 3ms

/webview/native/Source/WebCore/css/CSSParser.cpp

https://bitbucket.org/rbair/rbair-controls-8
C++ | 10081 lines | 8704 code | 919 blank | 458 comment | 3195 complexity | 80fbb512e7a4d7e468ae0655bce3d67d MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, GPL-2.0, LGPL-2.0
  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, 2010, 2011, 2012 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. * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Library General Public
  12. * License as published by the Free Software Foundation; either
  13. * version 2 of the License, or (at your option) any later version.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Library General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Library General Public License
  21. * along with this library; see the file COPYING.LIB. If not, write to
  22. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  23. * Boston, MA 02110-1301, USA.
  24. */
  25. #include "config.h"
  26. #include "CSSParser.h"
  27. #include "CSSAspectRatioValue.h"
  28. #include "CSSBorderImage.h"
  29. #include "CSSCanvasValue.h"
  30. #include "CSSCrossfadeValue.h"
  31. #include "CSSCursorImageValue.h"
  32. #include "CSSFontFaceRule.h"
  33. #include "CSSFontFaceSrcValue.h"
  34. #include "CSSFunctionValue.h"
  35. #include "CSSGradientValue.h"
  36. #include "CSSImageValue.h"
  37. #include "CSSInheritedValue.h"
  38. #include "CSSInitialValue.h"
  39. #include "CSSLineBoxContainValue.h"
  40. #include "CSSMediaRule.h"
  41. #include "CSSPageRule.h"
  42. #include "CSSPrimitiveValue.h"
  43. #include "CSSProperty.h"
  44. #include "CSSPropertySourceData.h"
  45. #include "CSSReflectValue.h"
  46. #include "CSSSelector.h"
  47. #include "CSSTimingFunctionValue.h"
  48. #include "CSSUnicodeRangeValue.h"
  49. #include "CSSValueKeywords.h"
  50. #include "CSSValueList.h"
  51. #include "CSSValuePool.h"
  52. #if ENABLE(CSS_VARIABLES)
  53. #include "CSSVariableValue.h"
  54. #endif
  55. #include "CSSWrapShapes.h"
  56. #include "Counter.h"
  57. #include "Document.h"
  58. #include "FloatConversion.h"
  59. #include "FontFeatureValue.h"
  60. #include "FontValue.h"
  61. #include "HTMLParserIdioms.h"
  62. #include "HashTools.h"
  63. #include "MediaList.h"
  64. #include "MediaQueryExp.h"
  65. #include "Page.h"
  66. #include "Pair.h"
  67. #include "Rect.h"
  68. #include "RenderTheme.h"
  69. #include "RuntimeEnabledFeatures.h"
  70. #include "SVGParserUtilities.h"
  71. #include "Settings.h"
  72. #include "ShadowValue.h"
  73. #include "StylePropertySet.h"
  74. #include "StylePropertyShorthand.h"
  75. #include "StyleRule.h"
  76. #include "StyleRuleImport.h"
  77. #include "StyleSheetContents.h"
  78. #include "TextEncoding.h"
  79. #include "WebKitCSSKeyframeRule.h"
  80. #include "WebKitCSSKeyframesRule.h"
  81. #include "WebKitCSSRegionRule.h"
  82. #include "WebKitCSSTransformValue.h"
  83. #include <limits.h>
  84. #include <wtf/BitArray.h>
  85. #include <wtf/HexNumber.h>
  86. #include <wtf/dtoa.h>
  87. #include <wtf/text/StringBuffer.h>
  88. #include <wtf/text/StringBuilder.h>
  89. #if ENABLE(CSS_IMAGE_SET)
  90. #include "CSSImageSetValue.h"
  91. #endif
  92. #if ENABLE(CSS_FILTERS)
  93. #include "WebKitCSSFilterValue.h"
  94. #if ENABLE(SVG)
  95. #include "WebKitCSSSVGDocumentValue.h"
  96. #endif
  97. #endif
  98. #if ENABLE(CSS_SHADERS)
  99. #include "WebKitCSSShaderValue.h"
  100. #endif
  101. #if ENABLE(DASHBOARD_SUPPORT)
  102. #include "DashboardRegion.h"
  103. #endif
  104. #define YYDEBUG 0
  105. #if YYDEBUG > 0
  106. extern int cssyydebug;
  107. #endif
  108. extern int cssyyparse(WebCore::CSSParser*);
  109. using namespace std;
  110. using namespace WTF;
  111. namespace {
  112. enum PropertyType {
  113. PropertyExplicit,
  114. PropertyImplicit
  115. };
  116. class ImplicitScope {
  117. WTF_MAKE_NONCOPYABLE(ImplicitScope);
  118. public:
  119. ImplicitScope(WebCore::CSSParser* parser, PropertyType propertyType)
  120. : m_parser(parser)
  121. {
  122. m_parser->m_implicitShorthand = propertyType == PropertyImplicit;
  123. }
  124. ~ImplicitScope()
  125. {
  126. m_parser->m_implicitShorthand = false;
  127. }
  128. private:
  129. WebCore::CSSParser* m_parser;
  130. };
  131. } // namespace
  132. namespace WebCore {
  133. static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
  134. static const double MAX_SCALE = 1000000;
  135. static bool equal(const CSSParserString& a, const char* b)
  136. {
  137. for (int i = 0; i < a.length; ++i) {
  138. if (!b[i])
  139. return false;
  140. if (a.characters[i] != b[i])
  141. return false;
  142. }
  143. return !b[a.length];
  144. }
  145. static bool equalIgnoringCase(const CSSParserString& a, const char* b)
  146. {
  147. for (int i = 0; i < a.length; ++i) {
  148. if (!b[i])
  149. return false;
  150. ASSERT(!isASCIIUpper(b[i]));
  151. if (toASCIILower(a.characters[i]) != b[i])
  152. return false;
  153. }
  154. return !b[a.length];
  155. }
  156. static bool hasPrefix(const char* string, unsigned length, const char* prefix)
  157. {
  158. for (unsigned i = 0; i < length; ++i) {
  159. if (!prefix[i])
  160. return true;
  161. if (string[i] != prefix[i])
  162. return false;
  163. }
  164. return false;
  165. }
  166. const CSSParserContext& strictCSSParserContext()
  167. {
  168. DEFINE_STATIC_LOCAL(CSSParserContext, strictContext, (CSSStrictMode));
  169. return strictContext;
  170. }
  171. CSSParserContext::CSSParserContext(CSSParserMode mode, const KURL& baseURL)
  172. : baseURL(baseURL)
  173. , mode(mode)
  174. , isHTMLDocument(false)
  175. , isCSSCustomFilterEnabled(false)
  176. , isCSSRegionsEnabled(false)
  177. , isCSSGridLayoutEnabled(false)
  178. #if ENABLE(CSS_VARIABLES)
  179. , isCSSVariablesEnabled(false)
  180. #endif
  181. , needsSiteSpecificQuirks(false)
  182. , enforcesCSSMIMETypeInNoQuirksMode(true)
  183. {
  184. }
  185. CSSParserContext::CSSParserContext(Document* document, const KURL& baseURL, const String& charset)
  186. : baseURL(baseURL.isNull() ? document->baseURL() : baseURL)
  187. , charset(charset)
  188. , mode(document->inQuirksMode() ? CSSQuirksMode : CSSStrictMode)
  189. , isHTMLDocument(document->isHTMLDocument())
  190. , isCSSCustomFilterEnabled(document->settings() ? document->settings()->isCSSCustomFilterEnabled() : false)
  191. , isCSSRegionsEnabled(document->cssRegionsEnabled())
  192. , isCSSGridLayoutEnabled(document->cssGridLayoutEnabled())
  193. #if ENABLE(CSS_VARIABLES)
  194. , isCSSVariablesEnabled(document->settings() ? document->settings()->cssVariablesEnabled() : false)
  195. #endif
  196. , needsSiteSpecificQuirks(document->settings() ? document->settings()->needsSiteSpecificQuirks() : false)
  197. , enforcesCSSMIMETypeInNoQuirksMode(!document->settings() || document->settings()->enforceCSSMIMETypeInNoQuirksMode())
  198. {
  199. }
  200. bool operator==(const CSSParserContext& a, const CSSParserContext& b)
  201. {
  202. return a.baseURL == b.baseURL
  203. && a.charset == b.charset
  204. && a.mode == b.mode
  205. && a.isHTMLDocument == b.isHTMLDocument
  206. && a.isCSSCustomFilterEnabled == b.isCSSCustomFilterEnabled
  207. && a.isCSSRegionsEnabled == b.isCSSRegionsEnabled
  208. && a.isCSSGridLayoutEnabled == b.isCSSGridLayoutEnabled
  209. #if ENABLE(CSS_VARIABLES)
  210. && a.isCSSVariablesEnabled == b.isCSSVariablesEnabled
  211. #endif
  212. && a.needsSiteSpecificQuirks == b.needsSiteSpecificQuirks
  213. && a.enforcesCSSMIMETypeInNoQuirksMode == b.enforcesCSSMIMETypeInNoQuirksMode;
  214. }
  215. CSSParser::CSSParser(const CSSParserContext& context)
  216. : m_context(context)
  217. , m_important(false)
  218. , m_id(CSSPropertyInvalid)
  219. , m_styleSheet(0)
  220. , m_selectorListForParseSelector(0)
  221. , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
  222. , m_inParseShorthand(0)
  223. , m_currentShorthand(CSSPropertyInvalid)
  224. , m_implicitShorthand(false)
  225. , m_hasFontFaceOnlyValues(false)
  226. , m_hadSyntacticallyValidCSSRule(false)
  227. , m_defaultNamespace(starAtom)
  228. , m_parsedTextPrefixLength(0)
  229. , m_propertyRange(UINT_MAX, UINT_MAX)
  230. , m_ruleSourceDataResult(0)
  231. , m_parsingMode(NormalMode)
  232. , m_currentCharacter(0)
  233. , m_tokenStart(0)
  234. , m_token(0)
  235. , m_lineNumber(0)
  236. , m_lastSelectorLineNumber(0)
  237. , m_allowImportRules(true)
  238. , m_allowNamespaceDeclarations(true)
  239. {
  240. #if YYDEBUG > 0
  241. cssyydebug = 1;
  242. #endif
  243. CSSPropertySourceData::init();
  244. }
  245. CSSParser::~CSSParser()
  246. {
  247. clearProperties();
  248. fastDeleteAllValues(m_floatingSelectors);
  249. deleteAllValues(m_floatingSelectorVectors);
  250. deleteAllValues(m_floatingValueLists);
  251. deleteAllValues(m_floatingFunctions);
  252. }
  253. void CSSParserString::lower()
  254. {
  255. // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
  256. // that can potentially change the length of the string rather than the character
  257. // by character kind. If we don't need Unicode lowercasing, it would be good to
  258. // simplify this function.
  259. if (charactersAreAllASCII(characters, length)) {
  260. // Fast case for all-ASCII.
  261. for (int i = 0; i < length; i++)
  262. characters[i] = toASCIILower(characters[i]);
  263. } else {
  264. for (int i = 0; i < length; i++)
  265. characters[i] = Unicode::toLower(characters[i]);
  266. }
  267. }
  268. void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix)
  269. {
  270. m_parsedTextPrefixLength = strlen(prefix);
  271. int length = string.length() + m_parsedTextPrefixLength + strlen(suffix) + 1;
  272. m_dataStart = adoptArrayPtr(new UChar[length]);
  273. for (unsigned i = 0; i < m_parsedTextPrefixLength; i++)
  274. m_dataStart[i] = prefix[i];
  275. memcpy(m_dataStart.get() + m_parsedTextPrefixLength, string.characters(), string.length() * sizeof(UChar));
  276. unsigned start = m_parsedTextPrefixLength + string.length();
  277. unsigned end = start + strlen(suffix);
  278. for (unsigned i = start; i < end; i++)
  279. m_dataStart[i] = suffix[i - start];
  280. m_dataStart[length - 1] = 0;
  281. m_currentCharacter = m_tokenStart = m_dataStart.get();
  282. }
  283. void CSSParser::parseSheet(StyleSheetContents* sheet, const String& string, int startLineNumber, RuleSourceDataList* ruleSourceDataResult)
  284. {
  285. setStyleSheet(sheet);
  286. m_defaultNamespace = starAtom; // Reset the default namespace.
  287. if (ruleSourceDataResult)
  288. m_currentRuleDataStack = adoptPtr(new RuleSourceDataList());
  289. m_ruleSourceDataResult = ruleSourceDataResult;
  290. m_lineNumber = startLineNumber;
  291. setupParser("", string, "");
  292. cssyyparse(this);
  293. m_currentRuleDataStack.clear();
  294. m_ruleSourceDataResult = 0;
  295. m_rule = 0;
  296. }
  297. PassRefPtr<StyleRuleBase> CSSParser::parseRule(StyleSheetContents* sheet, const String& string)
  298. {
  299. setStyleSheet(sheet);
  300. m_allowNamespaceDeclarations = false;
  301. setupParser("@-webkit-rule{", string, "} ");
  302. cssyyparse(this);
  303. return m_rule.release();
  304. }
  305. PassRefPtr<StyleKeyframe> CSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string)
  306. {
  307. setStyleSheet(sheet);
  308. setupParser("@-webkit-keyframe-rule{ ", string, "} ");
  309. cssyyparse(this);
  310. return m_keyframe.release();
  311. }
  312. static inline bool isColorPropertyID(CSSPropertyID propertyId)
  313. {
  314. switch (propertyId) {
  315. case CSSPropertyColor:
  316. case CSSPropertyBackgroundColor:
  317. case CSSPropertyBorderBottomColor:
  318. case CSSPropertyBorderLeftColor:
  319. case CSSPropertyBorderRightColor:
  320. case CSSPropertyBorderTopColor:
  321. case CSSPropertyOutlineColor:
  322. case CSSPropertyTextLineThroughColor:
  323. case CSSPropertyTextOverlineColor:
  324. case CSSPropertyTextUnderlineColor:
  325. case CSSPropertyWebkitBorderAfterColor:
  326. case CSSPropertyWebkitBorderBeforeColor:
  327. case CSSPropertyWebkitBorderEndColor:
  328. case CSSPropertyWebkitBorderStartColor:
  329. case CSSPropertyWebkitColumnRuleColor:
  330. case CSSPropertyWebkitTextEmphasisColor:
  331. case CSSPropertyWebkitTextFillColor:
  332. case CSSPropertyWebkitTextStrokeColor:
  333. return true;
  334. default:
  335. return false;
  336. }
  337. }
  338. static bool parseColorValue(StylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
  339. {
  340. ASSERT(!string.isEmpty());
  341. bool strict = isStrictParserMode(cssParserMode);
  342. if (!isColorPropertyID(propertyId))
  343. return false;
  344. CSSParserString cssString;
  345. cssString.characters = const_cast<UChar*>(string.characters());
  346. cssString.length = string.length();
  347. int valueID = cssValueKeywordID(cssString);
  348. bool validPrimitive = false;
  349. if (valueID == CSSValueWebkitText)
  350. validPrimitive = true;
  351. else if (valueID == CSSValueCurrentcolor)
  352. validPrimitive = true;
  353. else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
  354. || (valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText && !strict)) {
  355. validPrimitive = true;
  356. }
  357. if (validPrimitive) {
  358. RefPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID);
  359. declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
  360. return true;
  361. }
  362. RGBA32 color;
  363. if (!CSSParser::fastParseColor(color, string, strict && string[0] != '#'))
  364. return false;
  365. RefPtr<CSSValue> value = cssValuePool().createColorValue(color);
  366. declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
  367. return true;
  368. }
  369. static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
  370. {
  371. switch (propertyId) {
  372. case CSSPropertyFontSize:
  373. case CSSPropertyHeight:
  374. case CSSPropertyWidth:
  375. case CSSPropertyMinHeight:
  376. case CSSPropertyMinWidth:
  377. case CSSPropertyPaddingBottom:
  378. case CSSPropertyPaddingLeft:
  379. case CSSPropertyPaddingRight:
  380. case CSSPropertyPaddingTop:
  381. case CSSPropertyWebkitLogicalWidth:
  382. case CSSPropertyWebkitLogicalHeight:
  383. case CSSPropertyWebkitMinLogicalWidth:
  384. case CSSPropertyWebkitMinLogicalHeight:
  385. case CSSPropertyWebkitPaddingAfter:
  386. case CSSPropertyWebkitPaddingBefore:
  387. case CSSPropertyWebkitPaddingEnd:
  388. case CSSPropertyWebkitPaddingStart:
  389. acceptsNegativeNumbers = false;
  390. return true;
  391. #if ENABLE(CSS_EXCLUSIONS)
  392. case CSSPropertyWebkitWrapMargin:
  393. case CSSPropertyWebkitWrapPadding:
  394. acceptsNegativeNumbers = false;
  395. return RuntimeEnabledFeatures::cssExclusionsEnabled();
  396. #endif
  397. case CSSPropertyBottom:
  398. case CSSPropertyLeft:
  399. case CSSPropertyMarginBottom:
  400. case CSSPropertyMarginLeft:
  401. case CSSPropertyMarginRight:
  402. case CSSPropertyMarginTop:
  403. case CSSPropertyRight:
  404. case CSSPropertyTextIndent:
  405. case CSSPropertyTop:
  406. case CSSPropertyWebkitMarginAfter:
  407. case CSSPropertyWebkitMarginBefore:
  408. case CSSPropertyWebkitMarginEnd:
  409. case CSSPropertyWebkitMarginStart:
  410. acceptsNegativeNumbers = true;
  411. return true;
  412. default:
  413. return false;
  414. }
  415. }
  416. template <typename CharType>
  417. static inline bool parseSimpleLength(const CharType* characters, unsigned& length, CSSPrimitiveValue::UnitTypes& unit, double& number)
  418. {
  419. if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
  420. length -= 2;
  421. unit = CSSPrimitiveValue::CSS_PX;
  422. } else if (length > 1 && characters[length - 1] == '%') {
  423. length -= 1;
  424. unit = CSSPrimitiveValue::CSS_PERCENTAGE;
  425. }
  426. // We rely on charactersToDouble for validation as well. The function
  427. // will set "ok" to "false" if the entire passed-in character range does
  428. // not represent a double.
  429. bool ok;
  430. number = charactersToDouble(characters, length, &ok);
  431. return ok;
  432. }
  433. static bool parseSimpleLengthValue(StylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
  434. {
  435. ASSERT(!string.isEmpty());
  436. bool acceptsNegativeNumbers;
  437. if (!isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
  438. return false;
  439. unsigned length = string.length();
  440. double number;
  441. CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
  442. if (string.is8Bit()) {
  443. if (!parseSimpleLength(string.characters8(), length, unit, number))
  444. return false;
  445. } else {
  446. if (!parseSimpleLength(string.characters16(), length, unit, number))
  447. return false;
  448. }
  449. if (unit == CSSPrimitiveValue::CSS_NUMBER) {
  450. if (number && isStrictParserMode(cssParserMode))
  451. return false;
  452. unit = CSSPrimitiveValue::CSS_PX;
  453. }
  454. if (number < 0 && !acceptsNegativeNumbers)
  455. return false;
  456. RefPtr<CSSValue> value = cssValuePool().createValue(number, unit);
  457. declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
  458. return true;
  459. }
  460. static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext)
  461. {
  462. if (!valueID)
  463. return false;
  464. switch (propertyId) {
  465. case CSSPropertyBorderCollapse: // collapse | separate | inherit
  466. if (valueID == CSSValueCollapse || valueID == CSSValueSeparate)
  467. return true;
  468. break;
  469. case CSSPropertyBorderTopStyle: // <border-style> | inherit
  470. case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
  471. case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
  472. case CSSPropertyBorderLeftStyle:
  473. case CSSPropertyWebkitBorderAfterStyle:
  474. case CSSPropertyWebkitBorderBeforeStyle:
  475. case CSSPropertyWebkitBorderEndStyle:
  476. case CSSPropertyWebkitBorderStartStyle:
  477. case CSSPropertyWebkitColumnRuleStyle:
  478. if (valueID >= CSSValueNone && valueID <= CSSValueDouble)
  479. return true;
  480. break;
  481. case CSSPropertyBoxSizing:
  482. if (valueID == CSSValueBorderBox || valueID == CSSValueContentBox)
  483. return true;
  484. break;
  485. case CSSPropertyCaptionSide: // top | bottom | left | right | inherit
  486. if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom)
  487. return true;
  488. break;
  489. case CSSPropertyClear: // none | left | right | both | inherit
  490. if (valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth)
  491. return true;
  492. break;
  493. case CSSPropertyDirection: // ltr | rtl | inherit
  494. if (valueID == CSSValueLtr || valueID == CSSValueRtl)
  495. return true;
  496. break;
  497. case CSSPropertyDisplay:
  498. // inline | block | list-item | run-in | inline-block | table |
  499. // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
  500. // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none | inherit
  501. // -webkit-flex | -webkit-inline-flex | -webkit-grid | -webkit-inline-grid
  502. if ((valueID >= CSSValueInline && valueID <= CSSValueWebkitInlineBox) || valueID == CSSValueNone)
  503. return true;
  504. #if ENABLE(CSS3_FLEXBOX)
  505. if (valueID == CSSValueWebkitFlex || valueID == CSSValueWebkitInlineFlex)
  506. return true;
  507. #endif
  508. if (parserContext.isCSSGridLayoutEnabled && (valueID == CSSValueWebkitGrid || valueID == CSSValueWebkitInlineGrid))
  509. return true;
  510. break;
  511. case CSSPropertyEmptyCells: // show | hide | inherit
  512. if (valueID == CSSValueShow || valueID == CSSValueHide)
  513. return true;
  514. break;
  515. case CSSPropertyFloat: // left | right | none | center (for buggy CSS, maps to none)
  516. if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone || valueID == CSSValueCenter)
  517. return true;
  518. break;
  519. case CSSPropertyFontStyle: // normal | italic | oblique | inherit
  520. if (valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique)
  521. return true;
  522. break;
  523. case CSSPropertyImageRendering: // auto | optimizeContrast
  524. if (valueID == CSSValueAuto || valueID == CSSValueWebkitOptimizeContrast)
  525. return true;
  526. break;
  527. case CSSPropertyListStylePosition: // inside | outside | inherit
  528. if (valueID == CSSValueInside || valueID == CSSValueOutside)
  529. return true;
  530. break;
  531. case CSSPropertyListStyleType:
  532. // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
  533. // for the list of supported list-style-types.
  534. if ((valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone)
  535. return true;
  536. break;
  537. case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit
  538. if (valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble))
  539. return true;
  540. break;
  541. case CSSPropertyOverflowX:
  542. case CSSPropertyOverflowY: // visible | hidden | scroll | auto | marquee | overlay | inherit
  543. if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitMarquee)
  544. return true;
  545. break;
  546. case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit
  547. case CSSPropertyPageBreakBefore:
  548. case CSSPropertyWebkitColumnBreakAfter:
  549. case CSSPropertyWebkitColumnBreakBefore:
  550. if (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight)
  551. return true;
  552. break;
  553. case CSSPropertyPageBreakInside: // avoid | auto | inherit
  554. case CSSPropertyWebkitColumnBreakInside:
  555. if (valueID == CSSValueAuto || valueID == CSSValueAvoid)
  556. return true;
  557. break;
  558. case CSSPropertyPointerEvents:
  559. // none | visiblePainted | visibleFill | visibleStroke | visible |
  560. // painted | fill | stroke | auto | all | inherit
  561. if (valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueStroke))
  562. return true;
  563. break;
  564. case CSSPropertyPosition: // static | relative | absolute | fixed | inherit
  565. if (valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed)
  566. return true;
  567. break;
  568. case CSSPropertyResize: // none | both | horizontal | vertical | auto
  569. if (valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto)
  570. return true;
  571. break;
  572. case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit
  573. if (valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation)
  574. return true;
  575. break;
  576. case CSSPropertyTableLayout: // auto | fixed | inherit
  577. if (valueID == CSSValueAuto || valueID == CSSValueFixed)
  578. return true;
  579. break;
  580. case CSSPropertyTextLineThroughMode:
  581. case CSSPropertyTextOverlineMode:
  582. case CSSPropertyTextUnderlineMode:
  583. if (valueID == CSSValueContinuous || valueID == CSSValueSkipWhiteSpace)
  584. return true;
  585. break;
  586. case CSSPropertyTextLineThroughStyle:
  587. case CSSPropertyTextOverlineStyle:
  588. case CSSPropertyTextUnderlineStyle:
  589. if (valueID == CSSValueNone || valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDashed || valueID == CSSValueDotDash || valueID == CSSValueDotDotDash || valueID == CSSValueWave)
  590. return true;
  591. break;
  592. case CSSPropertyTextOverflow: // clip | ellipsis
  593. if (valueID == CSSValueClip || valueID == CSSValueEllipsis)
  594. return true;
  595. break;
  596. case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
  597. if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision)
  598. return true;
  599. break;
  600. case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit
  601. if ((valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone)
  602. return true;
  603. break;
  604. case CSSPropertyVisibility: // visible | hidden | collapse | inherit
  605. if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse)
  606. return true;
  607. break;
  608. case CSSPropertyWebkitAppearance:
  609. if ((valueID >= CSSValueCheckbox && valueID <= CSSValueTextarea) || valueID == CSSValueNone)
  610. return true;
  611. break;
  612. case CSSPropertyWebkitBackfaceVisibility:
  613. if (valueID == CSSValueVisible || valueID == CSSValueHidden)
  614. return true;
  615. break;
  616. case CSSPropertyWebkitBorderFit:
  617. if (valueID == CSSValueBorder || valueID == CSSValueLines)
  618. return true;
  619. break;
  620. case CSSPropertyWebkitBoxAlign:
  621. if (valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline)
  622. return true;
  623. break;
  624. #if ENABLE(CSS_BOX_DECORATION_BREAK)
  625. case CSSPropertyWebkitBoxDecorationBreak:
  626. if (valueID == CSSValueClone || valueID == CSSValueSlice)
  627. return true;
  628. break;
  629. #endif
  630. case CSSPropertyWebkitBoxDirection:
  631. if (valueID == CSSValueNormal || valueID == CSSValueReverse)
  632. return true;
  633. break;
  634. case CSSPropertyWebkitBoxLines:
  635. if (valueID == CSSValueSingle || valueID == CSSValueMultiple)
  636. return true;
  637. break;
  638. case CSSPropertyWebkitBoxOrient:
  639. if (valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis)
  640. return true;
  641. break;
  642. case CSSPropertyWebkitBoxPack:
  643. if (valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify)
  644. return true;
  645. break;
  646. case CSSPropertyWebkitColorCorrection:
  647. if (valueID == CSSValueSrgb || valueID == CSSValueDefault)
  648. return true;
  649. break;
  650. #if ENABLE(CSS3_FLEXBOX)
  651. case CSSPropertyWebkitAlignContent:
  652. if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch)
  653. return true;
  654. break;
  655. case CSSPropertyWebkitAlignItems:
  656. if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
  657. return true;
  658. break;
  659. case CSSPropertyWebkitAlignSelf:
  660. if (valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
  661. return true;
  662. break;
  663. case CSSPropertyWebkitFlexDirection:
  664. if (valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse)
  665. return true;
  666. break;
  667. case CSSPropertyWebkitFlexWrap:
  668. if (valueID == CSSValueNone || valueID == CSSValueWrap || valueID == CSSValueWrapReverse)
  669. return true;
  670. break;
  671. case CSSPropertyWebkitJustifyContent:
  672. if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround)
  673. return true;
  674. break;
  675. #endif
  676. case CSSPropertyWebkitFontKerning:
  677. if (valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone)
  678. return true;
  679. break;
  680. case CSSPropertyWebkitFontSmoothing:
  681. if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased)
  682. return true;
  683. break;
  684. case CSSPropertyWebkitHyphens:
  685. if (valueID == CSSValueNone || valueID == CSSValueManual || valueID == CSSValueAuto)
  686. return true;
  687. break;
  688. case CSSPropertyWebkitLineAlign:
  689. if (valueID == CSSValueNone || valueID == CSSValueEdges)
  690. return true;
  691. break;
  692. case CSSPropertyWebkitLineBreak: // normal | after-white-space
  693. if (valueID == CSSValueNormal || valueID == CSSValueAfterWhiteSpace)
  694. return true;
  695. break;
  696. case CSSPropertyWebkitLineSnap:
  697. if (valueID == CSSValueNone || valueID == CSSValueBaseline || valueID == CSSValueContain)
  698. return true;
  699. break;
  700. case CSSPropertyWebkitMarginAfterCollapse:
  701. case CSSPropertyWebkitMarginBeforeCollapse:
  702. case CSSPropertyWebkitMarginBottomCollapse:
  703. case CSSPropertyWebkitMarginTopCollapse:
  704. if (valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard)
  705. return true;
  706. break;
  707. case CSSPropertyWebkitMarqueeDirection:
  708. if (valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
  709. || valueID == CSSValueUp || valueID == CSSValueAuto)
  710. return true;
  711. break;
  712. case CSSPropertyWebkitMarqueeStyle:
  713. if (valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate)
  714. return true;
  715. break;
  716. case CSSPropertyWebkitNbspMode: // normal | space
  717. if (valueID == CSSValueNormal || valueID == CSSValueSpace)
  718. return true;
  719. break;
  720. #if ENABLE(OVERFLOW_SCROLLING)
  721. case CSSPropertyWebkitOverflowScrolling:
  722. if (valueID == CSSValueAuto || valueID == CSSValueTouch)
  723. return true;
  724. break;
  725. #endif
  726. case CSSPropertyWebkitPrintColorAdjust:
  727. if (valueID == CSSValueExact || valueID == CSSValueEconomy)
  728. return true;
  729. break;
  730. #if ENABLE(CSS_REGIONS)
  731. case CSSPropertyWebkitRegionBreakAfter:
  732. case CSSPropertyWebkitRegionBreakBefore:
  733. if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight))
  734. return true;
  735. break;
  736. case CSSPropertyWebkitRegionBreakInside:
  737. if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueAvoid))
  738. return true;
  739. break;
  740. case CSSPropertyWebkitRegionOverflow:
  741. if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueBreak))
  742. return true;
  743. break;
  744. #endif
  745. case CSSPropertyWebkitRtlOrdering:
  746. if (valueID == CSSValueLogical || valueID == CSSValueVisual)
  747. return true;
  748. break;
  749. case CSSPropertyWebkitTextCombine:
  750. if (valueID == CSSValueNone || valueID == CSSValueHorizontal)
  751. return true;
  752. break;
  753. case CSSPropertyWebkitTextEmphasisPosition:
  754. if (valueID == CSSValueOver || valueID == CSSValueUnder)
  755. return true;
  756. break;
  757. case CSSPropertyWebkitTextSecurity:
  758. // disc | circle | square | none | inherit
  759. if (valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone)
  760. return true;
  761. break;
  762. case CSSPropertyWebkitTextSizeAdjust:
  763. if (valueID == CSSValueAuto || valueID == CSSValueNone)
  764. return true;
  765. break;
  766. case CSSPropertyWebkitTransformStyle:
  767. if (valueID == CSSValueFlat || valueID == CSSValuePreserve3d)
  768. return true;
  769. break;
  770. case CSSPropertyWebkitUserDrag: // auto | none | element
  771. if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement)
  772. return true;
  773. break;
  774. case CSSPropertyWebkitUserModify: // read-only | read-write
  775. if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly)
  776. return true;
  777. break;
  778. case CSSPropertyWebkitUserSelect: // auto | none | text
  779. if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText)
  780. return true;
  781. break;
  782. #if ENABLE(CSS_EXCLUSIONS)
  783. case CSSPropertyWebkitWrapFlow:
  784. if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
  785. return false;
  786. if (valueID == CSSValueAuto || valueID == CSSValueBoth || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueMaximum || valueID == CSSValueClear)
  787. return true;
  788. break;
  789. case CSSPropertyWebkitWrapThrough:
  790. if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
  791. return false;
  792. if (valueID == CSSValueWrap || valueID == CSSValueNone)
  793. return true;
  794. break;
  795. #endif
  796. case CSSPropertyWebkitWritingMode:
  797. if (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
  798. return true;
  799. break;
  800. case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit
  801. if (valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap)
  802. return true;
  803. break;
  804. case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
  805. if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord)
  806. return true;
  807. break;
  808. case CSSPropertyWordWrap: // normal | break-word
  809. if (valueID == CSSValueNormal || valueID == CSSValueBreakWord)
  810. return true;
  811. break;
  812. default:
  813. ASSERT_NOT_REACHED();
  814. return false;
  815. }
  816. return false;
  817. }
  818. static inline bool isKeywordPropertyID(CSSPropertyID propertyId)
  819. {
  820. switch (propertyId) {
  821. case CSSPropertyBorderBottomStyle:
  822. case CSSPropertyBorderCollapse:
  823. case CSSPropertyBorderLeftStyle:
  824. case CSSPropertyBorderRightStyle:
  825. case CSSPropertyBorderTopStyle:
  826. case CSSPropertyBoxSizing:
  827. case CSSPropertyCaptionSide:
  828. case CSSPropertyClear:
  829. case CSSPropertyDirection:
  830. case CSSPropertyDisplay:
  831. case CSSPropertyEmptyCells:
  832. case CSSPropertyFloat:
  833. case CSSPropertyFontStyle:
  834. case CSSPropertyImageRendering:
  835. case CSSPropertyListStylePosition:
  836. case CSSPropertyListStyleType:
  837. case CSSPropertyOutlineStyle:
  838. case CSSPropertyOverflowX:
  839. case CSSPropertyOverflowY:
  840. case CSSPropertyPageBreakAfter:
  841. case CSSPropertyPageBreakBefore:
  842. case CSSPropertyPageBreakInside:
  843. case CSSPropertyPointerEvents:
  844. case CSSPropertyPosition:
  845. case CSSPropertyResize:
  846. case CSSPropertySpeak:
  847. case CSSPropertyTableLayout:
  848. case CSSPropertyTextLineThroughMode:
  849. case CSSPropertyTextLineThroughStyle:
  850. case CSSPropertyTextOverflow:
  851. case CSSPropertyTextOverlineMode:
  852. case CSSPropertyTextOverlineStyle:
  853. case CSSPropertyTextRendering:
  854. case CSSPropertyTextTransform:
  855. case CSSPropertyTextUnderlineMode:
  856. case CSSPropertyTextUnderlineStyle:
  857. case CSSPropertyVisibility:
  858. case CSSPropertyWebkitAppearance:
  859. case CSSPropertyWebkitBackfaceVisibility:
  860. case CSSPropertyWebkitBorderAfterStyle:
  861. case CSSPropertyWebkitBorderBeforeStyle:
  862. case CSSPropertyWebkitBorderEndStyle:
  863. case CSSPropertyWebkitBorderFit:
  864. case CSSPropertyWebkitBorderStartStyle:
  865. case CSSPropertyWebkitBoxAlign:
  866. #if ENABLE(CSS_BOX_DECORATION_BREAK)
  867. case CSSPropertyWebkitBoxDecorationBreak:
  868. #endif
  869. case CSSPropertyWebkitBoxDirection:
  870. case CSSPropertyWebkitBoxLines:
  871. case CSSPropertyWebkitBoxOrient:
  872. case CSSPropertyWebkitBoxPack:
  873. case CSSPropertyWebkitColorCorrection:
  874. case CSSPropertyWebkitColumnBreakAfter:
  875. case CSSPropertyWebkitColumnBreakBefore:
  876. case CSSPropertyWebkitColumnBreakInside:
  877. case CSSPropertyWebkitColumnRuleStyle:
  878. #if ENABLE(CSS3_FLEXBOX)
  879. case CSSPropertyWebkitAlignContent:
  880. case CSSPropertyWebkitAlignItems:
  881. case CSSPropertyWebkitAlignSelf:
  882. case CSSPropertyWebkitFlexDirection:
  883. case CSSPropertyWebkitFlexWrap:
  884. case CSSPropertyWebkitJustifyContent:
  885. #endif
  886. case CSSPropertyWebkitFontKerning:
  887. case CSSPropertyWebkitFontSmoothing:
  888. case CSSPropertyWebkitHyphens:
  889. case CSSPropertyWebkitLineAlign:
  890. case CSSPropertyWebkitLineBreak:
  891. case CSSPropertyWebkitLineSnap:
  892. case CSSPropertyWebkitMarginAfterCollapse:
  893. case CSSPropertyWebkitMarginBeforeCollapse:
  894. case CSSPropertyWebkitMarginBottomCollapse:
  895. case CSSPropertyWebkitMarginTopCollapse:
  896. case CSSPropertyWebkitMarqueeDirection:
  897. case CSSPropertyWebkitMarqueeStyle:
  898. case CSSPropertyWebkitNbspMode:
  899. #if ENABLE(OVERFLOW_SCROLLING)
  900. case CSSPropertyWebkitOverflowScrolling:
  901. #endif
  902. case CSSPropertyWebkitPrintColorAdjust:
  903. #if ENABLE(CSS_REGIONS)
  904. case CSSPropertyWebkitRegionBreakAfter:
  905. case CSSPropertyWebkitRegionBreakBefore:
  906. case CSSPropertyWebkitRegionBreakInside:
  907. case CSSPropertyWebkitRegionOverflow:
  908. #endif
  909. case CSSPropertyWebkitRtlOrdering:
  910. case CSSPropertyWebkitTextCombine:
  911. case CSSPropertyWebkitTextEmphasisPosition:
  912. case CSSPropertyWebkitTextSecurity:
  913. case CSSPropertyWebkitTextSizeAdjust:
  914. case CSSPropertyWebkitTransformStyle:
  915. case CSSPropertyWebkitUserDrag:
  916. case CSSPropertyWebkitUserModify:
  917. case CSSPropertyWebkitUserSelect:
  918. #if ENABLE(CSS_EXCLUSIONS)
  919. case CSSPropertyWebkitWrapFlow:
  920. case CSSPropertyWebkitWrapThrough:
  921. #endif
  922. case CSSPropertyWebkitWritingMode:
  923. case CSSPropertyWhiteSpace:
  924. case CSSPropertyWordBreak:
  925. case CSSPropertyWordWrap:
  926. return true;
  927. default:
  928. return false;
  929. }
  930. }
  931. static bool parseKeywordValue(StylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext)
  932. {
  933. ASSERT(!string.isEmpty());
  934. if (!isKeywordPropertyID(propertyId))
  935. return false;
  936. CSSParserString cssString;
  937. cssString.characters = const_cast<UChar*>(string.characters());
  938. cssString.length = string.length();
  939. int valueID = cssValueKeywordID(cssString);
  940. if (!valueID)
  941. return false;
  942. RefPtr<CSSValue> value;
  943. if (valueID == CSSValueInherit)
  944. value = cssValuePool().createInheritedValue();
  945. else if (valueID == CSSValueInitial)
  946. value = cssValuePool().createExplicitInitialValue();
  947. else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext))
  948. value = cssValuePool().createIdentifierValue(valueID);
  949. else
  950. return false;
  951. declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
  952. return true;
  953. }
  954. template <typename CharType>
  955. static bool parseTransformArguments(WebKitCSSTransformValue* transformValue, CharType* characters, unsigned length, unsigned start, unsigned expectedCount)
  956. {
  957. while (expectedCount) {
  958. size_t end = WTF::find(characters, length, expectedCount == 1 ? ')' : ',', start);
  959. if (end == notFound || (expectedCount == 1 && end != length - 1))
  960. return false;
  961. unsigned argumentLength = end - start;
  962. CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
  963. double number;
  964. if (!parseSimpleLength(characters + start, argumentLength, unit, number))
  965. return false;
  966. if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER))
  967. return false;
  968. transformValue->append(cssValuePool().createValue(number, unit));
  969. start = end + 1;
  970. --expectedCount;
  971. }
  972. return true;
  973. }
  974. static bool parseTransformValue(StylePropertySet* properties, CSSPropertyID propertyID, const String& string, bool important)
  975. {
  976. if (propertyID != CSSPropertyWebkitTransform)
  977. return false;
  978. static const unsigned shortestValidTransformStringLength = 12;
  979. static const unsigned likelyMultipartTransformStringLengthCutoff = 32;
  980. if (string.length() < shortestValidTransformStringLength || string.length() > likelyMultipartTransformStringLengthCutoff)
  981. return false;
  982. if (!string.startsWith("translate", false))
  983. return false;
  984. UChar c9 = toASCIILower(string[9]);
  985. UChar c10 = toASCIILower(string[10]);
  986. WebKitCSSTransformValue::TransformOperationType transformType;
  987. unsigned expectedArgumentCount = 1;
  988. unsigned argumentStart = 11;
  989. if (c9 == 'x' && c10 == '(')
  990. transformType = WebKitCSSTransformValue::TranslateXTransformOperation;
  991. else if (c9 == 'y' && c10 == '(')
  992. transformType = WebKitCSSTransformValue::TranslateYTransformOperation;
  993. else if (c9 == 'z' && c10 == '(')
  994. transformType = WebKitCSSTransformValue::TranslateZTransformOperation;
  995. else if (c9 == '(') {
  996. transformType = WebKitCSSTransformValue::TranslateTransformOperation;
  997. expectedArgumentCount = 2;
  998. argumentStart = 10;
  999. } else if (c9 == '3' && c10 == 'd' && string[11] == '(') {
  1000. transformType = WebKitCSSTransformValue::Translate3DTransformOperation;
  1001. expectedArgumentCount = 3;
  1002. argumentStart = 12;
  1003. } else
  1004. return false;
  1005. RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(transformType);
  1006. bool success;
  1007. if (string.is8Bit())
  1008. success = parseTransformArguments(transformValue.get(), string.characters8(), string.length(), argumentStart, expectedArgumentCount);
  1009. else
  1010. success = parseTransformArguments(transformValue.get(), string.characters16(), string.length(), argumentStart, expectedArgumentCount);
  1011. if (!success)
  1012. return false;
  1013. RefPtr<CSSValueList> result = CSSValueList::createSpaceSeparated();
  1014. result->append(transformValue.release());
  1015. properties->addParsedProperty(CSSProperty(CSSPropertyWebkitTransform, result.release(), important));
  1016. return true;
  1017. }
  1018. PassRefPtr<CSSValueList> CSSParser::parseFontFaceValue(const AtomicString& string)
  1019. {
  1020. if (string.isEmpty())
  1021. return 0;
  1022. RefPtr<StylePropertySet> dummyStyle = StylePropertySet::create();
  1023. if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, CSSQuirksMode, 0))
  1024. return 0;
  1025. return static_pointer_cast<CSSValueList>(dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily));
  1026. }
  1027. #if ENABLE(CSS_VARIABLES)
  1028. bool CSSParser::parseValue(StylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, Document* document)
  1029. {
  1030. ASSERT(!string.isEmpty());
  1031. CSSParserContext context(document);
  1032. if (parseSimpleLengthValue(declaration, propertyID, string, important, context.mode))
  1033. return true;
  1034. if (parseColorValue(declaration, propertyID, string, important, context.mode))
  1035. return true;
  1036. if (parseKeywordValue(declaration, propertyID, string, important, context))
  1037. return true;
  1038. CSSParser parser(context);
  1039. return parser.parseValue(declaration, propertyID, string, important, static_cast<StyleSheetContents*>(0));
  1040. }
  1041. #endif
  1042. bool CSSParser::parseValue(StylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
  1043. {
  1044. ASSERT(!string.isEmpty());
  1045. if (parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode))
  1046. return true;
  1047. if (parseColorValue(declaration, propertyID, string, important, cssParserMode))
  1048. return true;
  1049. if (parseKeywordValue(declaration, propertyID, string, important, contextStyleSheet->parserContext()))
  1050. return true;
  1051. if (parseTransformValue(declaration, propertyID, string, important))
  1052. return true;
  1053. CSSParserContext context(cssParserMode);
  1054. if (contextStyleSheet) {
  1055. context = contextStyleSheet->parserContext();
  1056. context.mode = cssParserMode;
  1057. }
  1058. CSSParser parser(context);
  1059. return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet);
  1060. }
  1061. bool CSSParser::parseValue(StylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet)
  1062. {
  1063. setStyleSheet(contextStyleSheet);
  1064. setupParser("@-webkit-value{", string, "} ");
  1065. m_id = propertyID;
  1066. m_important = important;
  1067. cssyyparse(this);
  1068. m_rule = 0;
  1069. bool ok = false;
  1070. if (m_hasFontFaceOnlyValues)
  1071. deleteFontFaceOnlyValues();
  1072. if (!m_parsedProperties.isEmpty()) {
  1073. ok = true;
  1074. declaration->addParsedProperties(m_parsedProperties);
  1075. clearProperties();
  1076. }
  1077. return ok;
  1078. }
  1079. // The color will only be changed when string contains a valid CSS color, so callers
  1080. // can set it to a default color and ignore the boolean result.
  1081. bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
  1082. {
  1083. // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
  1084. if (fastParseColor(color, string, strict))
  1085. return true;
  1086. CSSParser parser(CSSStrictMode);
  1087. // In case the fast-path parser didn't understand the color, try the full parser.
  1088. if (!parser.parseColor(string))
  1089. return false;
  1090. CSSValue* value = parser.m_parsedProperties.first().value();
  1091. if (!value->isPrimitiveValue())
  1092. return false;
  1093. CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
  1094. if (!primitiveValue->isRGBColor())
  1095. return false;
  1096. color = primitiveValue->getRGBA32Value();
  1097. return true;
  1098. }
  1099. bool CSSParser::parseColor(const String& string)
  1100. {
  1101. setupParser("@-webkit-decls{color:", string, "} ");
  1102. cssyyparse(this);
  1103. m_rule = 0;
  1104. return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor;
  1105. }
  1106. bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document)
  1107. {
  1108. if (!document || !document->page())
  1109. return false;
  1110. CSSParserString cssColor;
  1111. cssColor.characters = const_cast<UChar*>(string.characters());
  1112. cssColor.length = string.length();
  1113. int id = cssValueKeywordID(cssColor);
  1114. if (id <= 0)
  1115. return false;
  1116. color = document->page()->theme()->systemColor(id).rgb();
  1117. return true;
  1118. }
  1119. void CSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
  1120. {
  1121. m_selectorListForParseSelector = &selectorList;
  1122. setupParser("@-webkit-selector{", string, "}");
  1123. cssyyparse(this);
  1124. m_selectorListForParseSelector = 0;
  1125. }
  1126. bool CSSParser::parseDeclaration(StylePropertySet* declaration, const String& string, PassRefPtr<CSSRuleSourceData> prpRuleSourceData, StyleSheetContents* contextStyleSheet)
  1127. {
  1128. // Length of the "@-webkit-decls{" prefix.
  1129. static const unsigned prefixLength = 15;
  1130. setStyleSheet(contextStyleSheet);
  1131. RefPtr<CSSRuleSourceData> ruleSourceData = prpRuleSourceData;
  1132. if (ruleSourceData) {
  1133. m_currentRuleDataStack = adoptPtr(new RuleSourceDataList());
  1134. m_currentRuleDataStack->append(ruleSourceData);
  1135. }
  1136. setupParser("@-webkit-decls{", string, "} ");
  1137. cssyyparse(this);
  1138. m_rule = 0;
  1139. bool ok = false;
  1140. if (m_hasFontFaceOnlyValues)
  1141. deleteFontFaceOnlyValues();
  1142. if (!m_parsedProperties.isEmpty()) {
  1143. ok = true;
  1144. declaration->addParsedProperties(m_parsedProperties);
  1145. clearProperties();
  1146. }
  1147. if (ruleSourceData) {
  1148. ASSERT(m_currentRuleDataStack->size() == 1);
  1149. ruleSourceData->ruleBodyRange.start = 0;
  1150. ruleSourceData->ruleBodyRange.end = string.length();
  1151. for (size_t i = 0, size = ruleSourceData->styleSourceData->propertyData.size(); i < size; ++i) {
  1152. CSSPropertySourceData& propertyData = ruleSourceData->styleSourceData->propertyData.at(i);
  1153. propertyData.range.start -= prefixLength;
  1154. propertyData.range.end -= prefixLength;
  1155. }
  1156. fixUnparsedPropertyRanges(ruleSourceData.get());
  1157. m_currentRuleDataStack.clear();
  1158. }
  1159. return ok;
  1160. }
  1161. PassOwnPtr<MediaQuery> CSSParser::parseMediaQuery(const String& string)
  1162. {
  1163. if (string.isEmpty())
  1164. return nullptr;
  1165. ASSERT(!m_mediaQuery);
  1166. // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
  1167. // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
  1168. setupParser("@-webkit-mediaquery ", string, "} ");
  1169. cssyyparse(this);
  1170. return m_mediaQuery.release();
  1171. }
  1172. #if ENABLE(CSS_VARIABLES)
  1173. static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties, HashSet<AtomicString>& seenVariables)
  1174. #else
  1175. static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties)
  1176. #endif
  1177. {
  1178. // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
  1179. for (int i = input.size() - 1; i >= 0; --i) {
  1180. const CSSProperty& property = input[i];
  1181. if (property.isImportant() != important)
  1182. continue;
  1183. #if ENABLE(CSS_VARIABLES)
  1184. if (property.id() == CSSPropertyVariable) {
  1185. const AtomicString& name = static_cast<CSSVariableValue*>(property.value())->name();
  1186. if (seenVariables.contains(name))
  1187. continue;
  1188. seenVariables.add(name);
  1189. output[--unusedEntries] = property;
  1190. continue;
  1191. }
  1192. #endif
  1193. const unsigned propertyIDIndex = property.id() - firstCSSProperty;
  1194. if (seenProperties.get(propertyIDIndex))
  1195. continue;
  1196. seenProperties.set(propertyIDIndex);
  1197. output[--unusedEntries] = property;
  1198. }
  1199. }
  1200. PassRefPtr<StylePropertySet> CSSParser::createStylePropertySet()
  1201. {
  1202. BitArray<numCSSProperties> seenProperties;
  1203. size_t unusedEntries = m_parsedProperties.size();
  1204. Vector<CSSProperty, 256> results(unusedEntries);
  1205. // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found.
  1206. #if ENABLE(CSS_VARIABLES)
  1207. HashSet<AtomicString> seenVariables;
  1208. filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
  1209. filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
  1210. #else
  1211. filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties);
  1212. filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties);
  1213. #endif
  1214. if (unusedEntries)
  1215. results.remove(0, unusedEntries);
  1216. return StylePropertySet::createImmutable(results.data(), results.size(), m_context.mode);
  1217. }
  1218. void CSSParser::addProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
  1219. {
  1220. m_parsedProperties.append(CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand || implicit));
  1221. }
  1222. void CSSParser::rollbackLastProperties(int num)
  1223. {
  1224. ASSERT(num >= 0);
  1225. ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
  1226. m_parsedProperties.shrink(m_parsedProperties.size() - num);
  1227. }
  1228. void CSSParser::clearProperties()
  1229. {
  1230. m_parsedProperties.clear();
  1231. m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
  1232. m_hasFontFaceOnlyValues = false;
  1233. }
  1234. void CSSParser::setStyleSheet(StyleSheetContents* styleSheet)
  1235. {
  1236. m_styleSheet = styleSheet;
  1237. }
  1238. KURL CSSParser::completeURL(const CSSParserContext& context, const String& url)
  1239. {
  1240. if (url.isNull())
  1241. return KURL();
  1242. if (context.charset.isEmpty())
  1243. return KURL(context.baseURL, url);
  1244. return KURL(context.baseURL, url, context.charset);
  1245. }
  1246. KURL CSSParser::completeURL(const String& url) const
  1247. {
  1248. return completeURL(m_context, url);
  1249. }
  1250. bool CSSParser::validCalculationUnit(CSSParserValue* value, Units unitflags)
  1251. {
  1252. bool mustBeNonNegative = unitflags & FNonNeg;
  1253. if (!parseCalculation(value, mustBeNonNegative ? CalculationRangeNonNegative : CalculationRangeAll))
  1254. return false;
  1255. bool b = false;
  1256. switch (m_parsedCalculation->category()) {
  1257. case CalcLength:
  1258. b = (unitflags & FLength);
  1259. break;
  1260. case CalcPercent:
  1261. b = (unitflags & FPercent);
  1262. if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
  1263. b = false;
  1264. break;
  1265. case CalcNumber:
  1266. b = (unitflags & FNumber);
  1267. if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
  1268. b = true;
  1269. if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
  1270. b = false;
  1271. break;
  1272. case CalcPercentLength:
  1273. b = (unitflags & FPercent) && (unitflags & FLength);
  1274. break;
  1275. case CalcPercentNumber:
  1276. b = (unitflags & FPercent) && (unitflags & FNumber);
  1277. break;
  1278. case CalcOther:
  1279. break;
  1280. }
  1281. if (!b)
  1282. m_parsedCalculation.release();
  1283. return b;
  1284. }
  1285. inline bool CSSParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
  1286. {
  1287. // Qirks mode and svg presentation attributes accept unit less values.
  1288. return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || cssParserMode == CSSQuirksMode || cssParserMode == SVGAttributeMode);
  1289. }
  1290. bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
  1291. {
  1292. if (isCalculation(value))
  1293. return validCalculationUnit(value, unitflags);
  1294. bool b = false;
  1295. switch (value->unit) {
  1296. #if ENABLE(CSS_VARIABLES)
  1297. case CSSPrimitiveValue::CSS_VARIABLE_NAME:
  1298. // Variables are checked at the point they are dereferenced because unit type is not available here.
  1299. b = true;
  1300. break;
  1301. #endif
  1302. case CSSPrimitiveValue::CSS_NUMBER:
  1303. b = (unitflags & FNumber);
  1304. if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
  1305. value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
  1306. ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
  1307. b = true;
  1308. }
  1309. if (!b && (unitflags & FInteger) && value->isInt)
  1310. b = true;
  1311. break;
  1312. case CSSPrimitiveValue::CSS_PERCENTAGE:
  1313. b = (unitflags & FPercent);
  1314. break;
  1315. case CSSParserValue::Q_EMS:
  1316. case CSSPrimitiveValue::CSS_EMS:
  1317. case CSSPrimitiveValue::CSS_REMS:
  1318. case CSSPrimitiveValue::CSS_EXS:
  1319. case CSSPrimitiveValue::CSS_PX:
  1320. case CSSPrimitiveValue::CSS_CM:
  1321. case CSSPrimitiveValue::CSS_MM:
  1322. case CSSPrimitiveValue::CSS_IN:
  1323. case CSSPrimitiveValue::CSS_PT:
  1324. case CSSPrimitiveValue::CSS_PC:
  1325. case CSSPrimitiveValue::CSS_VW:
  1326. case CSSPrimitiveValue::CSS_VH:
  1327. case CSSPrimitiveValue::CSS_VMIN:
  1328. b = (unitflags & FLength);
  1329. break;
  1330. case CSSPrimitiveValue::CSS_MS:
  1331. case CSSPrimitiveValue::CSS_S:
  1332. b = (unitflags & FTime);
  1333. break;
  1334. case CSSPrimitiveValue::CSS_DEG:
  1335. case CSSPrimitiveValue::CSS_RAD:
  1336. case CSSPrimitiveValue::CSS_GRAD:
  1337. case CSSPrimitiveValue::CSS_TURN:
  1338. b = (unitflags & FAngle);
  1339. break;
  1340. #if ENABLE(CSS_IMAGE_RESOLUTION)
  1341. case CSSPrimitiveValue::CSS_DPPX:
  1342. case CSSPrimitiveValue::CSS_DPI:
  1343. case CSSPrimitiveValue::CSS_DPCM:
  1344. b = (unitflags & FResolution);
  1345. break;
  1346. #endif
  1347. case CSSPrimitiveValue::CSS_HZ:
  1348. case CSSPrimitiveValue::CSS_KHZ:
  1349. case CSSPrimitiveValue::CSS_DIMENSION:
  1350. default:
  1351. break;
  1352. }
  1353. if (b && unitflags & FNonNeg && value->fValue < 0)
  1354. b = false;
  1355. return b;
  1356. }
  1357. inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveNumericValue(CSSParserValue* value)
  1358. {
  1359. #if ENABLE(CSS_VARIABLES)
  1360. if (value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
  1361. return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_VARIABLE_NAME);
  1362. #endif
  1363. if (m_parsedCalculation) {
  1364. ASSERT(isCalculation(value));
  1365. return CSSPrimitiveValue::create(m_parsedCalculation.release());
  1366. }
  1367. #if ENABLE(CSS_IMAGE_RESOLUTION)
  1368. ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
  1369. || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS)
  1370. || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMIN)
  1371. || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
  1372. #else
  1373. ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
  1374. || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS)
  1375. || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMIN));
  1376. #endif
  1377. return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
  1378. }
  1379. inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveStringValue(CSSParserValue* value)
  1380. {
  1381. ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
  1382. return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
  1383. }
  1384. static int unitFromString(CSSParserValue* value)
  1385. {
  1386. if (value->unit != CSSPrimitiveValue::CSS_IDENT || value->id)
  1387. return 0;
  1388. if (equal(value->string, "em"))
  1389. return CSSPrimitiveValue::CSS_EMS;
  1390. if (equal(value->string, "rem"))
  1391. return CSSPrimitiveValue::CSS_REMS;
  1392. if (equal(value->string, "ex"))
  1393. return CSSPrimitiveValue::CSS_EXS;
  1394. if (equal(value->string, "px"))
  1395. return CSSPrimitiveValue::CSS_PX;
  1396. if (equal(value->string, "cm"))
  1397. return CSSPrimitiveValue::CSS_CM;
  1398. if (equal(value->string, "mm"))
  1399. return CSSPrimitiveValue::CSS_MM;
  1400. if (equal(value->string, "in"))
  1401. return CSSPrimitiveValue::CSS_IN;
  1402. if (equal(value->string, "pt"))
  1403. return CSSPrimitiveValue::CSS_PT;
  1404. if (equal(value->string, "pc"))
  1405. return CSSPrimitiveValue::CSS_PC;
  1406. if (equal(value->string, "deg"))
  1407. return CSSPrimitiveValue::CSS_DEG;
  1408. if (equal(value->string, "rad"))
  1409. return CSSPrimitiveValue::CSS_RAD;
  1410. if (equal(value->string, "grad"))
  1411. return CSSPrimitiveValue::CSS_GRAD;
  1412. if (equal(value->string, "turn"))
  1413. return CSSPrimitiveValue::CSS_TURN;
  1414. if (equal(value->string, "ms"))
  1415. return CSSPrimitiveValue::CSS_MS;
  1416. if (equal(value->string, "s"))
  1417. return CSSPrimitiveValue::CSS_S;
  1418. if (equal(value->string, "Hz"))
  1419. return CSSPrimitiveValue::CSS_HZ;
  1420. if (equal(value->string, "kHz"))
  1421. return CSSPrimitiveValue::CSS_KHZ;
  1422. if (equal(value->string, "vw"))
  1423. return CSSPrimitiveValue::CSS_VW;
  1424. if (equal(value->string, "vh"))
  1425. return CSSPrimitiveValue::CSS_VH;
  1426. if (equal(value->string, "vmin"))
  1427. return CSSPrimitiveValue::CSS_VMIN;
  1428. #if ENABLE(CSS_IMAGE_RESOLUTION)
  1429. if (equal(value->string, "dppx"))
  1430. return CSSPrimitiveValue::CSS_DPPX;
  1431. if (equal(value->string, "dpi"))
  1432. return CSSPrimitiveValue::CSS_DPI;
  1433. if (equal(value->string, "dpcm"))
  1434. return CSSPrimitiveValue::CSS_DPCM;
  1435. #endif
  1436. return 0;
  1437. }
  1438. static inline bool isComma(CSSParserValue* value)
  1439. {
  1440. return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
  1441. }
  1442. bool CSSParser::validWidth(CSSParserValue* value)
  1443. {
  1444. int id = value->id;
  1445. if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
  1446. return true;
  1447. return !id && validUnit(value, FLength | FPercent | FNonNeg);
  1448. }
  1449. // FIXME: Combine this with validWidth when we support fit-content, et al, for heights.
  1450. bool CSSParser::validHeight(CSSParserValue* value)
  1451. {
  1452. int id = value->id;
  1453. if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
  1454. return true;
  1455. return !id && validUnit(value, FLength | FPercent | FNonNeg);
  1456. }
  1457. void CSSParser::checkForOrphanedUnits()
  1458. {
  1459. if (inStrictMode() || inShorthand())
  1460. return;
  1461. // The purpose of this code is to implement the WinIE quirk that allows unit types to be separated from their numeric values
  1462. // 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.
  1463. CSSParserValue* numericVal = 0;
  1464. unsigned size = m_valueList->size();
  1465. for (unsigned i = 0; i < size; i++) {
  1466. CSSParserValue* value = m_valueList->valueAt(i);
  1467. if (numericVal) {
  1468. // Change the unit type of the numeric val to match.
  1469. int unit = unitFromString(value);
  1470. if (unit) {
  1471. numericVal->unit = unit;
  1472. numericVal = 0;
  1473. // Now delete the bogus unit value.
  1474. m_valueList->deleteValueAt(i);
  1475. 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).
  1476. size--;
  1477. continue;
  1478. }
  1479. }
  1480. numericVal = (value->unit == CSSPrimitiveValue::CSS_NUMBER) ? value : 0;
  1481. }
  1482. }
  1483. inline PassRefPtr<CSSPrimitiveValue> CSSParser::parseValidPrimitive(int identifier, CSSParserValue* value)
  1484. {
  1485. if (identifier)
  1486. return cssValuePool().createIdentifierValue(identifier);
  1487. if (value->unit == CSSPrimitiveValue::CSS_STRING)
  1488. return createPrimitiveStringValue(value);
  1489. if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
  1490. return createPrimitiveNumericValue(value);
  1491. if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS)
  1492. return createPrimitiveNumericValue(value);
  1493. if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMIN)
  1494. return createPrimitiveNumericValue(value);
  1495. #if ENABLE(CSS_IMAGE_RESOLUTION)
  1496. if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
  1497. return createPrimitiveNumericValue(value);
  1498. #endif
  1499. if (value->unit >= CSSParserValue::Q_EMS)
  1500. return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
  1501. if (isCalculation(value))
  1502. return CSSPrimitiveValue::create(m_parsedCalculation.release());
  1503. return 0;
  1504. }
  1505. bool CSSParser::parseValue(CSSPropertyID propId, bool important)
  1506. {
  1507. if (!m_valueList)
  1508. return false;
  1509. CSSParserValue* value = m_valueList->current();
  1510. if (!value)
  1511. return false;
  1512. // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
  1513. // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
  1514. ASSERT(!m_parsedCalculation);
  1515. int id = value->id;
  1516. // In quirks mode, we will look for units that have been incorrectly separated from the number they belong to
  1517. // by a space. We go ahead and associate the unit with the number even though it is invalid CSS.
  1518. checkForOrphanedUnits();
  1519. int num = inShorthand() ? 1 : m_valueList->size();
  1520. if (id == CSSValueInherit) {
  1521. if (num != 1)
  1522. return false;
  1523. addProperty(propId, cssValuePool().createInheritedValue(), important);
  1524. return true;
  1525. }
  1526. else if (id == CSSValueInitial) {
  1527. if (num != 1)
  1528. return false;
  1529. addProperty(propId, cssValuePool().createExplicitInitialValue(), important);
  1530. return true;
  1531. }
  1532. #if ENABLE(CSS_VARIABLES)
  1533. if (!id && value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME && num == 1) {
  1534. addProperty(propId, CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_VARIABLE_NAME), important);
  1535. m_valueList->next();
  1536. return true;
  1537. }
  1538. ASSERT(propId != CSSPropertyVariable);
  1539. #endif
  1540. if (isKeywordPropertyID(propId)) {
  1541. if (!isValidKeywordPropertyAndValue(propId, id, m_context))
  1542. return false;
  1543. if (m_valueList->next() && !inShorthand())
  1544. return false;
  1545. addProperty(propId, cssValuePool().createIdentifierValue(id), important);
  1546. return true;
  1547. }
  1548. bool validPrimitive = false;
  1549. RefPtr<CSSValue> parsedValue;
  1550. switch (propId) {
  1551. case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
  1552. return parseSize(propId, important);
  1553. case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit
  1554. if (id)
  1555. validPrimitive = true;
  1556. else
  1557. return parseQuotes(propId, important);
  1558. break;
  1559. case CSSPropertyUnicodeBidi: // normal | embed | (bidi-override || isolate) | plaintext | inherit
  1560. if (id == CSSValueNormal
  1561. || id == CSSValueEmbed
  1562. || id == CSSValueWebkitPlaintext)
  1563. validPrimitive = true;
  1564. else {
  1565. RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
  1566. bool isValid = true;
  1567. while (isValid && value) {
  1568. switch (value->id) {
  1569. case CSSValueBidiOverride:
  1570. case CSSValueWebkitIsolate:
  1571. list->append(cssValuePool().createIdentifierValue(value->id));
  1572. break;
  1573. default:
  1574. isValid = false;
  1575. }
  1576. value = m_valueList->next();
  1577. }
  1578. if (list->length() && isValid) {
  1579. parsedValue = list.release();
  1580. m_valueList->next();
  1581. }
  1582. }
  1583. break;
  1584. case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
  1585. // close-quote | no-open-quote | no-close-quote ]+ | inherit
  1586. return parseContent(propId, important);
  1587. case CSSPropertyClip: // <shape> | auto | inherit
  1588. if (id == CSSValueAuto)
  1589. validPrimitive = true;
  1590. else if (value->unit == CSSParserValue::Function)
  1591. return parseClipShape(propId, important);
  1592. break;
  1593. /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
  1594. * correctly and allows optimization in WebCore::applyRule(..)
  1595. */
  1596. case CSSPropertyOverflow: {
  1597. ShorthandScope scope(this, propId);
  1598. if (num != 1 || !parseValue(CSSPropertyOverflowX, important))
  1599. return false;
  1600. CSSValue* value = m_parsedProperties.last().value();
  1601. addProperty(CSSPropertyOverflowY, value, important);
  1602. return true;
  1603. }
  1604. case CSSPropertyTextAlign:
  1605. // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
  1606. // | start | end | <string> | inherit | -webkit-auto (converted to start)
  1607. if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
  1608. || value->unit == CSSPrimitiveValue::CSS_STRING)
  1609. validPrimitive = true;
  1610. break;
  1611. case CSSPropertyFontWeight: { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
  1612. if (m_valueList->size() != 1)
  1613. return false;
  1614. return parseFontWeight(important);
  1615. }
  1616. case CSSPropertyBorderSpacing: {
  1617. if (num == 1) {
  1618. ShorthandScope scope(this, CSSPropertyBorderSpacing);
  1619. if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
  1620. return false;
  1621. CSSValue* value = m_parsedProperties.last().value();
  1622. addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
  1623. return true;
  1624. }
  1625. else if (num == 2) {
  1626. ShorthandScope scope(this, CSSPropertyBorderSpacing);
  1627. if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
  1628. return false;
  1629. return true;
  1630. }
  1631. return false;
  1632. }
  1633. case CSSPropertyWebkitBorderHorizontalSpacing:
  1634. case CSSPropertyWebkitBorderVerticalSpacing:
  1635. validPrimitive = validUnit(value, FLength | FNonNeg);
  1636. break;
  1637. case CSSPropertyOutlineColor: // <color> | invert | inherit
  1638. // Outline color has "invert" as additional keyword.
  1639. // Also, we want to allow the special focus color even in strict parsing mode.
  1640. if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
  1641. validPrimitive = true;
  1642. break;
  1643. }
  1644. /* nobreak */
  1645. case CSSPropertyBackgroundColor: // <color> | inherit
  1646. case CSSPropertyBorderTopColor: // <color> | inherit
  1647. case CSSPropertyBorderRightColor:
  1648. case CSSPropertyBorderBottomColor:
  1649. case CSSPropertyBorderLeftColor:
  1650. case CSSPropertyWebkitBorderStartColor:
  1651. case CSSPropertyWebkitBorderEndColor:
  1652. case CSSPropertyWebkitBorderBeforeColor:
  1653. case CSSPropertyWebkitBorderAfterColor:
  1654. case CSSPropertyColor: // <color> | inherit
  1655. case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors
  1656. case CSSPropertyTextUnderlineColor:
  1657. case CSSPropertyTextOverlineColor:
  1658. case CSSPropertyWebkitColumnRuleColor:
  1659. case CSSPropertyWebkitTextEmphasisColor:
  1660. case CSSPropertyWebkitTextFillColor:
  1661. case CSSPropertyWebkitTextStrokeColor:
  1662. if (id == CSSValueWebkitText)
  1663. validPrimitive = true; // Always allow this, even when strict parsing is on,
  1664. // since we use this in our UA sheets.
  1665. else if (id == CSSValueCurrentcolor)
  1666. validPrimitive = true;
  1667. else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu ||
  1668. (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
  1669. validPrimitive = true;
  1670. } else {
  1671. parsedValue = parseColor();
  1672. if (parsedValue)
  1673. m_valueList->next();
  1674. }
  1675. break;
  1676. case CSSPropertyCursor: {
  1677. // [<uri>,]* [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
  1678. // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
  1679. // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
  1680. // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
  1681. // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
  1682. RefPtr<CSSValueList> list;
  1683. while (value && value->unit == CSSPrimitiveValue::CSS_URI) {
  1684. if (!list)
  1685. list = CSSValueList::createCommaSeparated();
  1686. String uri = value->string;
  1687. Vector<int> coords;
  1688. value = m_valueList->next();
  1689. while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
  1690. coords.append(int(value->fValue));
  1691. value = m_valueList->next();
  1692. }
  1693. IntPoint hotSpot(-1, -1);
  1694. int nrcoords = coords.size();
  1695. if (nrcoords > 0 && nrcoords != 2)
  1696. return false;
  1697. if (nrcoords == 2)
  1698. hotSpot = IntPoint(coords[0], coords[1]);
  1699. if (!uri.isNull())
  1700. list->append(CSSCursorImageValue::create(completeURL(uri), hotSpot));
  1701. if ((inStrictMode() && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ',')))
  1702. return false;
  1703. value = m_valueList->next(); // comma
  1704. }
  1705. if (list) {
  1706. if (!value) { // no value after url list (MSIE 5 compatibility)
  1707. if (list->length() != 1)
  1708. return false;
  1709. } else if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
  1710. list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
  1711. else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
  1712. list->append(cssValuePool().createIdentifierValue(value->id));
  1713. m_valueList->next();
  1714. parsedValue = list.release();
  1715. break;
  1716. } else if (value) {
  1717. id = value->id;
  1718. if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
  1719. id = CSSValuePointer;
  1720. validPrimitive = true;
  1721. } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
  1722. validPrimitive = true;
  1723. } else {
  1724. ASSERT_NOT_REACHED();
  1725. return false;
  1726. }
  1727. break;
  1728. }
  1729. case CSSPropertyBackgroundAttachment:
  1730. case CSSPropertyBackgroundClip:
  1731. case CSSPropertyWebkitBackgroundClip:
  1732. case CSSPropertyWebkitBackgroundComposite:
  1733. case CSSPropertyBackgroundImage:
  1734. case CSSPropertyBackgroundOrigin:
  1735. case CSSPropertyWebkitBackgroundOrigin:
  1736. case CSSPropertyBackgroundPosition:
  1737. case CSSPropertyBackgroundPositionX:
  1738. case CSSPropertyBackgroundPositionY:
  1739. case CSSPropertyBackgroundSize:
  1740. case CSSPropertyWebkitBackgroundSize:
  1741. case CSSPropertyBackgroundRepeat:
  1742. case CSSPropertyBackgroundRepeatX:
  1743. case CSSPropertyBackgroundRepeatY:
  1744. case CSSPropertyWebkitMaskAttachment:
  1745. case CSSPropertyWebkitMaskClip:
  1746. case CSSPropertyWebkitMaskComposite:
  1747. case CSSPropertyWebkitMaskImage:
  1748. case CSSPropertyWebkitMaskOrigin:
  1749. case CSSPropertyWebkitMaskPosition:
  1750. case CSSPropertyWebkitMaskPositionX:
  1751. case CSSPropertyWebkitMaskPositionY:
  1752. case CSSPropertyWebkitMaskSize:
  1753. case CSSPropertyWebkitMaskRepeat:
  1754. case CSSPropertyWebkitMaskRepeatX:
  1755. case CSSPropertyWebkitMaskRepeatY: {
  1756. RefPtr<CSSValue> val1;
  1757. RefPtr<CSSValue> val2;
  1758. CSSPropertyID propId1, propId2;
  1759. bool result = false;
  1760. if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
  1761. OwnPtr<ShorthandScope> shorthandScope;
  1762. if (propId == CSSPropertyBackgroundPosition ||
  1763. propId == CSSPropertyBackgroundRepeat ||
  1764. propId == CSSPropertyWebkitMaskPosition ||
  1765. propId == CSSPropertyWebkitMaskRepeat) {
  1766. shorthandScope = adoptPtr(new ShorthandScope(this, propId));
  1767. }
  1768. addProperty(propId1, val1.release(), important);
  1769. if (val2)
  1770. addProperty(propId2, val2.release(), important);
  1771. result = true;
  1772. }
  1773. m_implicitShorthand = false;
  1774. return result;
  1775. }
  1776. case CSSPropertyListStyleImage: // <uri> | none | inherit
  1777. case CSSPropertyBorderImageSource:
  1778. case CSSPropertyWebkitMaskBoxImageSource:
  1779. if (id == CSSValueNone) {
  1780. parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
  1781. m_valueList->next();
  1782. } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
  1783. parsedValue = CSSImageValue::create(completeURL(value->string));
  1784. m_valueList->next();
  1785. } else if (isGeneratedImageValue(value)) {
  1786. if (parseGeneratedImage(m_valueList.get(), parsedValue))
  1787. m_valueList->next();
  1788. else
  1789. return false;
  1790. }
  1791. #if ENABLE(CSS_IMAGE_SET)
  1792. else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
  1793. parsedValue = parseImageSet(m_valueList.get());
  1794. if (!parsedValue)
  1795. return false;
  1796. m_valueList->next();
  1797. }
  1798. #endif
  1799. break;
  1800. case CSSPropertyWebkitTextStrokeWidth:
  1801. case CSSPropertyOutlineWidth: // <border-width> | inherit
  1802. case CSSPropertyBorderTopWidth: //// <border-width> | inherit
  1803. case CSSPropertyBorderRightWidth: // Which is defined as
  1804. case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
  1805. case CSSPropertyBorderLeftWidth:
  1806. case CSSPropertyWebkitBorderStartWidth:
  1807. case CSSPropertyWebkitBorderEndWidth:
  1808. case CSSPropertyWebkitBorderBeforeWidth:
  1809. case CSSPropertyWebkitBorderAfterWidth:
  1810. case CSSPropertyWebkitColumnRuleWidth:
  1811. if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
  1812. validPrimitive = true;
  1813. else
  1814. validPrimitive = validUnit(value, FLength | FNonNeg);
  1815. break;
  1816. case CSSPropertyLetterSpacing: // normal | <length> | inherit
  1817. case CSSPropertyWordSpacing: // normal | <length> | inherit
  1818. if (id == CSSValueNormal)
  1819. validPrimitive = true;
  1820. else
  1821. validPrimitive = validUnit(value, FLength);
  1822. break;
  1823. case CSSPropertyTextIndent: // <length> | <percentage> | inherit
  1824. validPrimitive = (!id && validUnit(value, FLength | FPercent));
  1825. break;
  1826. case CSSPropertyPaddingTop: //// <padding-width> | inherit
  1827. case CSSPropertyPaddingRight: // Which is defined as
  1828. case CSSPropertyPaddingBottom: // <length> | <percentage>
  1829. case CSSPropertyPaddingLeft: ////
  1830. case CSSPropertyWebkitPaddingStart:
  1831. case CSSPropertyWebkitPaddingEnd:
  1832. case CSSPropertyWebkitPaddingBefore:
  1833. case CSSPropertyWebkitPaddingAfter:
  1834. validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
  1835. break;
  1836. case CSSPropertyMaxWidth:
  1837. case CSSPropertyWebkitMaxLogicalWidth:
  1838. validPrimitive = (id == CSSValueNone || validWidth(value));
  1839. break;
  1840. case CSSPropertyMinWidth:
  1841. case CSSPropertyWebkitMinLogicalWidth:
  1842. case CSSPropertyWidth:
  1843. case CSSPropertyWebkitLogicalWidth:
  1844. validPrimitive = (id == CSSValueAuto || validWidth(value));
  1845. break;
  1846. case CSSPropertyMaxHeight:
  1847. case CSSPropertyWebkitMaxLogicalHeight:
  1848. validPrimitive = (id == CSSValueNone || validHeight(value));
  1849. break;
  1850. case CSSPropertyMinHeight:
  1851. case CSSPropertyWebkitMinLogicalHeight:
  1852. case CSSPropertyHeight:
  1853. case CSSPropertyWebkitLogicalHeight:
  1854. validPrimitive = (id == CSSValueAuto || validHeight(value));
  1855. break;
  1856. case CSSPropertyFontSize:
  1857. return parseFontSize(important);
  1858. case CSSPropertyFontVariant: // normal | small-caps | inherit
  1859. return parseFontVariant(important);
  1860. case CSSPropertyVerticalAlign:
  1861. // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
  1862. // <percentage> | <length> | inherit
  1863. if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
  1864. validPrimitive = true;
  1865. else
  1866. validPrimitive = (!id && validUnit(value, FLength | FPercent));
  1867. break;
  1868. case CSSPropertyBottom: // <length> | <percentage> | auto | inherit
  1869. case CSSPropertyLeft: // <length> | <percentage> | auto | inherit
  1870. case CSSPropertyRight: // <length> | <percentage> | auto | inherit
  1871. case CSSPropertyTop: // <length> | <percentage> | auto | inherit
  1872. case CSSPropertyMarginTop: //// <margin-width> | inherit
  1873. case CSSPropertyMarginRight: // Which is defined as
  1874. case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit
  1875. case CSSPropertyMarginLeft: ////
  1876. case CSSPropertyWebkitMarginStart:
  1877. case CSSPropertyWebkitMarginEnd:
  1878. case CSSPropertyWebkitMarginBefore:
  1879. case CSSPropertyWebkitMarginAfter:
  1880. if (id == CSSValueAuto)
  1881. validPrimitive = true;
  1882. else
  1883. validPrimitive = (!id && validUnit(value, FLength | FPercent));
  1884. break;
  1885. case CSSPropertyZIndex: // auto | <integer> | inherit
  1886. if (id == CSSValueAuto) {
  1887. validPrimitive = true;
  1888. break;
  1889. }
  1890. /* nobreak */
  1891. case CSSPropertyOrphans: // <integer> | inherit
  1892. case CSSPropertyWidows: // <integer> | inherit
  1893. // ### not supported later on
  1894. validPrimitive = (!id && validUnit(value, FInteger, CSSQuirksMode));
  1895. break;
  1896. case CSSPropertyLineHeight:
  1897. return parseLineHeight(important);
  1898. case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
  1899. if (id != CSSValueNone)
  1900. return parseCounter(propId, 1, important);
  1901. validPrimitive = true;
  1902. break;
  1903. case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit
  1904. if (id != CSSValueNone)
  1905. return parseCounter(propId, 0, important);
  1906. validPrimitive = true;
  1907. break;
  1908. case CSSPropertyFontFamily:
  1909. // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
  1910. {
  1911. parsedValue = parseFontFamily();
  1912. break;
  1913. }
  1914. case CSSPropertyTextDecoration:
  1915. case CSSPropertyWebkitTextDecorationsInEffect:
  1916. // none | [ underline || overline || line-through || blink ] | inherit
  1917. if (id == CSSValueNone) {
  1918. validPrimitive = true;
  1919. } else {
  1920. RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
  1921. bool isValid = true;
  1922. while (isValid && value) {
  1923. switch (value->id) {
  1924. case CSSValueBlink:
  1925. break;
  1926. case CSSValueUnderline:
  1927. case CSSValueOverline:
  1928. case CSSValueLineThrough:
  1929. list->append(cssValuePool().createIdentifierValue(value->id));
  1930. break;
  1931. default:
  1932. isValid = false;
  1933. }
  1934. value = m_valueList->next();
  1935. }
  1936. if (list->length() && isValid) {
  1937. parsedValue = list.release();
  1938. m_valueList->next();
  1939. }
  1940. }
  1941. break;
  1942. case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit
  1943. if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
  1944. validPrimitive = true;
  1945. else
  1946. validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode));
  1947. break;
  1948. case CSSPropertySrc: // Only used within @font-face, so cannot use inherit | initial or be !important. This is a list of urls or local references.
  1949. return parseFontFaceSrc();
  1950. case CSSPropertyUnicodeRange:
  1951. return parseFontFaceUnicodeRange();
  1952. /* CSS3 properties */
  1953. case CSSPropertyBorderImage: {
  1954. RefPtr<CSSValue> result;
  1955. return parseBorderImage(propId, result, important);
  1956. }
  1957. case CSSPropertyWebkitBorderImage:
  1958. case CSSPropertyWebkitMaskBoxImage: {
  1959. RefPtr<CSSValue> result;
  1960. if (parseBorderImage(propId, result)) {
  1961. addProperty(propId, result, important);
  1962. return true;
  1963. }
  1964. break;
  1965. }
  1966. case CSSPropertyBorderImageOutset:
  1967. case CSSPropertyWebkitMaskBoxImageOutset: {
  1968. RefPtr<CSSPrimitiveValue> result;
  1969. if (parseBorderImageOutset(result)) {
  1970. addProperty(propId, result, important);
  1971. return true;
  1972. }
  1973. break;
  1974. }
  1975. case CSSPropertyBorderImageRepeat:
  1976. case CSSPropertyWebkitMaskBoxImageRepeat: {
  1977. RefPtr<CSSValue> result;
  1978. if (parseBorderImageRepeat(result)) {
  1979. addProperty(propId, result, important);
  1980. return true;
  1981. }
  1982. break;
  1983. }
  1984. case CSSPropertyBorderImageSlice:
  1985. case CSSPropertyWebkitMaskBoxImageSlice: {
  1986. RefPtr<CSSBorderImageSliceValue> result;
  1987. if (parseBorderImageSlice(propId, result)) {
  1988. addProperty(propId, result, important);
  1989. return true;
  1990. }
  1991. break;
  1992. }
  1993. case CSSPropertyBorderImageWidth:
  1994. case CSSPropertyWebkitMaskBoxImageWidth: {
  1995. RefPtr<CSSPrimitiveValue> result;
  1996. if (parseBorderImageWidth(result)) {
  1997. addProperty(propId, result, important);
  1998. return true;
  1999. }
  2000. break;
  2001. }
  2002. case CSSPropertyBorderTopRightRadius:
  2003. case CSSPropertyBorderTopLeftRadius:
  2004. case CSSPropertyBorderBottomLeftRadius:
  2005. case CSSPropertyBorderBottomRightRadius: {
  2006. if (num != 1 && num != 2)
  2007. return false;
  2008. validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
  2009. if (!validPrimitive)
  2010. return false;
  2011. RefPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
  2012. RefPtr<CSSPrimitiveValue> parsedValue2;
  2013. if (num == 2) {
  2014. value = m_valueList->next();
  2015. validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
  2016. if (!validPrimitive)
  2017. return false;
  2018. parsedValue2 = createPrimitiveNumericValue(value);
  2019. } else
  2020. parsedValue2 = parsedValue1;
  2021. RefPtr<Pair> pair = Pair::create(parsedValue1.release(), parsedValue2.release());
  2022. RefPtr<CSSPrimitiveValue> val = cssValuePool().createValue(pair.release());
  2023. addProperty(propId, val.release(), important);
  2024. return true;
  2025. }
  2026. case CSSPropertyTabSize:
  2027. validPrimitive = validUnit(value, FInteger | FNonNeg);
  2028. break;
  2029. case CSSPropertyWebkitAspectRatio:
  2030. return parseAspectRatio(important);
  2031. case CSSPropertyBorderRadius:
  2032. case CSSPropertyWebkitBorderRadius:
  2033. return parseBorderRadius(propId, important);
  2034. case CSSPropertyOutlineOffset:
  2035. validPrimitive = validUnit(value, FLength | FPercent);
  2036. break;
  2037. case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
  2038. case CSSPropertyBoxShadow:
  2039. case CSSPropertyWebkitBoxShadow:
  2040. if (id == CSSValueNone)
  2041. validPrimitive = true;
  2042. else {
  2043. RefPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
  2044. if (shadowValueList) {
  2045. addProperty(propId, shadowValueList.release(), important);
  2046. m_valueList->next();
  2047. return true;
  2048. }
  2049. return false;
  2050. }
  2051. break;
  2052. case CSSPropertyWebkitBoxReflect:
  2053. if (id == CSSValueNone)
  2054. validPrimitive = true;
  2055. else
  2056. return parseReflect(propId, important);
  2057. break;
  2058. case CSSPropertyOpacity:
  2059. validPrimitive = validUnit(value, FNumber);
  2060. break;
  2061. case CSSPropertyWebkitBoxFlex:
  2062. validPrimitive = validUnit(value, FNumber);
  2063. break;
  2064. case CSSPropertyWebkitBoxFlexGroup:
  2065. validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode);
  2066. break;
  2067. case CSSPropertyWebkitBoxOrdinalGroup:
  2068. validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode) && value->fValue;
  2069. break;
  2070. #if ENABLE(CSS_FILTERS)
  2071. case CSSPropertyWebkitFilter:
  2072. if (id == CSSValueNone)
  2073. validPrimitive = true;
  2074. else {
  2075. RefPtr<CSSValue> val = parseFilter();
  2076. if (val) {
  2077. addProperty(propId, val, important);
  2078. return true;
  2079. }
  2080. return false;
  2081. }
  2082. break;
  2083. #endif
  2084. #if ENABLE(CSS3_FLEXBOX)
  2085. case CSSPropertyWebkitFlex: {
  2086. ShorthandScope scope(this, propId);
  2087. if (id == CSSValueNone) {
  2088. addProperty(CSSPropertyWebkitFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
  2089. addProperty(CSSPropertyWebkitFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
  2090. addProperty(CSSPropertyWebkitFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
  2091. return true;
  2092. }
  2093. return parseFlex(m_valueList.get(), important);
  2094. }
  2095. case CSSPropertyWebkitFlexBasis:
  2096. // FIXME: Support intrinsic dimensions too.
  2097. if (id == CSSValueAuto)
  2098. validPrimitive = true;
  2099. else
  2100. validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
  2101. break;
  2102. case CSSPropertyWebkitFlexGrow:
  2103. case CSSPropertyWebkitFlexShrink:
  2104. validPrimitive = validUnit(value, FNumber | FNonNeg);
  2105. break;
  2106. case CSSPropertyWebkitOrder:
  2107. validPrimitive = validUnit(value, FNumber);
  2108. break;
  2109. #endif
  2110. case CSSPropertyWebkitMarquee:
  2111. return parseShorthand(propId, webkitMarqueeShorthand(), important);
  2112. case CSSPropertyWebkitMarqueeIncrement:
  2113. if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
  2114. validPrimitive = true;
  2115. else
  2116. validPrimitive = validUnit(value, FLength | FPercent);
  2117. break;
  2118. case CSSPropertyWebkitMarqueeRepetition:
  2119. if (id == CSSValueInfinite)
  2120. validPrimitive = true;
  2121. else
  2122. validPrimitive = validUnit(value, FInteger | FNonNeg);
  2123. break;
  2124. case CSSPropertyWebkitMarqueeSpeed:
  2125. if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
  2126. validPrimitive = true;
  2127. else
  2128. validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
  2129. break;
  2130. #if ENABLE(CSS_REGIONS)
  2131. case CSSPropertyWebkitFlowInto:
  2132. if (!cssRegionsEnabled())
  2133. return false;
  2134. return parseFlowThread(propId, important);
  2135. case CSSPropertyWebkitFlowFrom:
  2136. if (!cssRegionsEnabled())
  2137. return false;
  2138. return parseRegionThread(propId, important);
  2139. #endif
  2140. case CSSPropertyWebkitTransform:
  2141. if (id == CSSValueNone)
  2142. validPrimitive = true;
  2143. else {
  2144. PassRefPtr<CSSValue> val = parseTransform();
  2145. if (val) {
  2146. addProperty(propId, val, important);
  2147. return true;
  2148. }
  2149. return false;
  2150. }
  2151. break;
  2152. case CSSPropertyWebkitTransformOrigin:
  2153. case CSSPropertyWebkitTransformOriginX:
  2154. case CSSPropertyWebkitTransformOriginY:
  2155. case CSSPropertyWebkitTransformOriginZ: {
  2156. RefPtr<CSSValue> val1;
  2157. RefPtr<CSSValue> val2;
  2158. RefPtr<CSSValue> val3;
  2159. CSSPropertyID propId1, propId2, propId3;
  2160. if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
  2161. addProperty(propId1, val1.release(), important);
  2162. if (val2)
  2163. addProperty(propId2, val2.release(), important);
  2164. if (val3)
  2165. addProperty(propId3, val3.release(), important);
  2166. return true;
  2167. }
  2168. return false;
  2169. }
  2170. case CSSPropertyWebkitPerspective:
  2171. if (id == CSSValueNone)
  2172. validPrimitive = true;
  2173. else {
  2174. // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
  2175. if (validUnit(value, FNumber | FLength | FNonNeg)) {
  2176. RefPtr<CSSValue> val = createPrimitiveNumericValue(value);
  2177. if (val) {
  2178. addProperty(propId, val.release(), important);
  2179. return true;
  2180. }
  2181. return false;
  2182. }
  2183. }
  2184. break;
  2185. case CSSPropertyWebkitPerspectiveOrigin:
  2186. case CSSPropertyWebkitPerspectiveOriginX:
  2187. case CSSPropertyWebkitPerspectiveOriginY: {
  2188. RefPtr<CSSValue> val1;
  2189. RefPtr<CSSValue> val2;
  2190. CSSPropertyID propId1, propId2;
  2191. if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
  2192. addProperty(propId1, val1.release(), important);
  2193. if (val2)
  2194. addProperty(propId2, val2.release(), important);
  2195. return true;
  2196. }
  2197. return false;
  2198. }
  2199. case CSSPropertyWebkitAnimationDelay:
  2200. case CSSPropertyWebkitAnimationDirection:
  2201. case CSSPropertyWebkitAnimationDuration:
  2202. case CSSPropertyWebkitAnimationFillMode:
  2203. case CSSPropertyWebkitAnimationName:
  2204. case CSSPropertyWebkitAnimationPlayState:
  2205. case CSSPropertyWebkitAnimationIterationCount:
  2206. case CSSPropertyWebkitAnimationTimingFunction:
  2207. case CSSPropertyWebkitTransitionDelay:
  2208. case CSSPropertyWebkitTransitionDuration:
  2209. case CSSPropertyWebkitTransitionTimingFunction:
  2210. case CSSPropertyWebkitTransitionProperty: {
  2211. RefPtr<CSSValue> val;
  2212. if (parseAnimationProperty(propId, val)) {
  2213. addProperty(propId, val.release(), important);
  2214. return true;
  2215. }
  2216. return false;
  2217. }
  2218. case CSSPropertyWebkitGridColumns:
  2219. case CSSPropertyWebkitGridRows:
  2220. if (!cssGridLayoutEnabled())
  2221. return false;
  2222. return parseGridTrackList(propId, important);
  2223. case CSSPropertyWebkitGridColumn:
  2224. case CSSPropertyWebkitGridRow:
  2225. if (!cssGridLayoutEnabled())
  2226. return false;
  2227. validPrimitive = id == CSSValueAuto || validUnit(value, FInteger);
  2228. break;
  2229. case CSSPropertyWebkitMarginCollapse: {
  2230. if (num == 1) {
  2231. ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
  2232. if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important))
  2233. return false;
  2234. CSSValue* value = m_parsedProperties.last().value();
  2235. addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
  2236. return true;
  2237. }
  2238. else if (num == 2) {
  2239. ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
  2240. if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important) || !parseValue(webkitMarginCollapseShorthand().properties()[1], important))
  2241. return false;
  2242. return true;
  2243. }
  2244. return false;
  2245. }
  2246. case CSSPropertyTextLineThroughWidth:
  2247. case CSSPropertyTextOverlineWidth:
  2248. case CSSPropertyTextUnderlineWidth:
  2249. if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
  2250. id == CSSValueMedium || id == CSSValueThick)
  2251. validPrimitive = true;
  2252. else
  2253. validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent);
  2254. break;
  2255. case CSSPropertyWebkitColumnCount:
  2256. if (id == CSSValueAuto)
  2257. validPrimitive = true;
  2258. else
  2259. validPrimitive = !id && validUnit(value, FInteger | FNonNeg, CSSQuirksMode);
  2260. break;
  2261. case CSSPropertyWebkitColumnGap: // normal | <length>
  2262. if (id == CSSValueNormal)
  2263. validPrimitive = true;
  2264. else
  2265. validPrimitive = validUnit(value, FLength | FNonNeg);
  2266. break;
  2267. case CSSPropertyWebkitColumnAxis:
  2268. if (id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
  2269. validPrimitive = true;
  2270. break;
  2271. case CSSPropertyWebkitColumnProgression:
  2272. if (id == CSSValueNormal || id == CSSValueReverse)
  2273. validPrimitive = true;
  2274. break;
  2275. case CSSPropertyWebkitColumnSpan: // all | 1
  2276. if (id == CSSValueAll)
  2277. validPrimitive = true;
  2278. else
  2279. validPrimitive = validUnit(value, FNumber | FNonNeg) && value->fValue == 1;
  2280. break;
  2281. case CSSPropertyWebkitColumnWidth: // auto | <length>
  2282. if (id == CSSValueAuto)
  2283. validPrimitive = true;
  2284. else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property.
  2285. validPrimitive = validUnit(value, FLength, CSSStrictMode);
  2286. break;
  2287. // End of CSS3 properties
  2288. // Apple specific properties. These will never be standardized and are purely to
  2289. // support custom WebKit-based Apple applications.
  2290. case CSSPropertyWebkitLineClamp:
  2291. // When specifying number of lines, don't allow 0 as a valid value
  2292. // When specifying either type of unit, require non-negative integers
  2293. validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, CSSQuirksMode));
  2294. break;
  2295. case CSSPropertyWebkitFontSizeDelta: // <length>
  2296. validPrimitive = validUnit(value, FLength);
  2297. break;
  2298. case CSSPropertyWebkitHighlight:
  2299. if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
  2300. validPrimitive = true;
  2301. break;
  2302. case CSSPropertyWebkitHyphenateCharacter:
  2303. if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
  2304. validPrimitive = true;
  2305. break;
  2306. case CSSPropertyWebkitHyphenateLimitBefore:
  2307. case CSSPropertyWebkitHyphenateLimitAfter:
  2308. if (id == CSSValueAuto || validUnit(value, FInteger | FNonNeg, CSSStrictMode))
  2309. validPrimitive = true;
  2310. break;
  2311. case CSSPropertyWebkitHyphenateLimitLines:
  2312. if (id == CSSValueNoLimit || validUnit(value, FInteger | FNonNeg, CSSStrictMode))
  2313. validPrimitive = true;
  2314. break;
  2315. case CSSPropertyWebkitLineGrid:
  2316. if (id == CSSValueNone)
  2317. validPrimitive = true;
  2318. else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
  2319. String lineGridValue = String(value->string);
  2320. if (!lineGridValue.isEmpty()) {
  2321. addProperty(propId, cssValuePool().createValue(lineGridValue, CSSPrimitiveValue::CSS_STRING), important);
  2322. return true;
  2323. }
  2324. }
  2325. break;
  2326. case CSSPropertyWebkitLocale:
  2327. if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
  2328. validPrimitive = true;
  2329. break;
  2330. #if ENABLE(DASHBOARD_SUPPORT)
  2331. case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region>
  2332. if (value->unit == CSSParserValue::Function || id == CSSValueNone)
  2333. return parseDashboardRegions(propId, important);
  2334. break;
  2335. #endif
  2336. // End Apple-specific properties
  2337. #if ENABLE(TOUCH_EVENTS)
  2338. case CSSPropertyWebkitTapHighlightColor:
  2339. if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu
  2340. || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
  2341. validPrimitive = true;
  2342. } else {
  2343. parsedValue = parseColor();
  2344. if (parsedValue)
  2345. m_valueList->next();
  2346. }
  2347. break;
  2348. #endif
  2349. /* shorthand properties */
  2350. case CSSPropertyBackground: {
  2351. // Position must come before color in this array because a plain old "0" is a legal color
  2352. // in quirks mode but it's usually the X coordinate of a position.
  2353. const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
  2354. CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
  2355. CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
  2356. return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
  2357. }
  2358. case CSSPropertyWebkitMask: {
  2359. const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
  2360. CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition,
  2361. CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip };
  2362. return parseFillShorthand(propId, properties, 6, important);
  2363. }
  2364. case CSSPropertyBorder:
  2365. // [ 'border-width' || 'border-style' || <color> ] | inherit
  2366. {
  2367. if (parseShorthand(propId, borderAbridgedShorthand(), important)) {
  2368. // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as
  2369. // though a value of none was specified for the image.
  2370. addProperty(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
  2371. return true;
  2372. }
  2373. return false;
  2374. }
  2375. case CSSPropertyBorderTop:
  2376. // [ 'border-top-width' || 'border-style' || <color> ] | inherit
  2377. return parseShorthand(propId, borderTopShorthand(), important);
  2378. case CSSPropertyBorderRight:
  2379. // [ 'border-right-width' || 'border-style' || <color> ] | inherit
  2380. return parseShorthand(propId, borderRightShorthand(), important);
  2381. case CSSPropertyBorderBottom:
  2382. // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
  2383. return parseShorthand(propId, borderBottomShorthand(), important);
  2384. case CSSPropertyBorderLeft:
  2385. // [ 'border-left-width' || 'border-style' || <color> ] | inherit
  2386. return parseShorthand(propId, borderLeftShorthand(), important);
  2387. case CSSPropertyWebkitBorderStart:
  2388. return parseShorthand(propId, webkitBorderStartShorthand(), important);
  2389. case CSSPropertyWebkitBorderEnd:
  2390. return parseShorthand(propId, webkitBorderEndShorthand(), important);
  2391. case CSSPropertyWebkitBorderBefore:
  2392. return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
  2393. case CSSPropertyWebkitBorderAfter:
  2394. return parseShorthand(propId, webkitBorderAfterShorthand(), important);
  2395. case CSSPropertyOutline:
  2396. // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
  2397. return parseShorthand(propId, outlineShorthand(), important);
  2398. case CSSPropertyBorderColor:
  2399. // <color>{1,4} | inherit
  2400. return parse4Values(propId, borderColorShorthand().properties(), important);
  2401. case CSSPropertyBorderWidth:
  2402. // <border-width>{1,4} | inherit
  2403. return parse4Values(propId, borderWidthShorthand().properties(), important);
  2404. case CSSPropertyBorderStyle:
  2405. // <border-style>{1,4} | inherit
  2406. return parse4Values(propId, borderStyleShorthand().properties(), important);
  2407. case CSSPropertyMargin:
  2408. // <margin-width>{1,4} | inherit
  2409. return parse4Values(propId, marginShorthand().properties(), important);
  2410. case CSSPropertyPadding:
  2411. // <padding-width>{1,4} | inherit
  2412. return parse4Values(propId, paddingShorthand().properties(), important);
  2413. #if ENABLE(CSS3_FLEXBOX)
  2414. case CSSPropertyWebkitFlexFlow:
  2415. return parseShorthand(propId, webkitFlexFlowShorthand(), important);
  2416. #endif
  2417. case CSSPropertyFont:
  2418. // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
  2419. // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
  2420. if (id >= CSSValueCaption && id <= CSSValueStatusBar)
  2421. validPrimitive = true;
  2422. else
  2423. return parseFont(important);
  2424. break;
  2425. case CSSPropertyListStyle:
  2426. return parseShorthand(propId, listStyleShorthand(), important);
  2427. case CSSPropertyWebkitColumns:
  2428. return parseShorthand(propId, webkitColumnsShorthand(), important);
  2429. case CSSPropertyWebkitColumnRule:
  2430. return parseShorthand(propId, webkitColumnRuleShorthand(), important);
  2431. case CSSPropertyWebkitTextStroke:
  2432. return parseShorthand(propId, webkitTextStrokeShorthand(), important);
  2433. case CSSPropertyWebkitAnimation:
  2434. return parseAnimationShorthand(important);
  2435. case CSSPropertyWebkitTransition:
  2436. return parseTransitionShorthand(important);
  2437. case CSSPropertyInvalid:
  2438. return false;
  2439. case CSSPropertyPage:
  2440. return parsePage(propId, important);
  2441. case CSSPropertyFontStretch:
  2442. case CSSPropertyTextLineThrough:
  2443. case CSSPropertyTextOverline:
  2444. case CSSPropertyTextUnderline:
  2445. return false;
  2446. // CSS Text Layout Module Level 3: Vertical writing support
  2447. case CSSPropertyWebkitTextEmphasis:
  2448. return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
  2449. case CSSPropertyWebkitTextEmphasisStyle:
  2450. return parseTextEmphasisStyle(important);
  2451. case CSSPropertyWebkitTextOrientation:
  2452. // FIXME: For now just support upright and vertical-right.
  2453. if (id == CSSValueVerticalRight || id == CSSValueUpright)
  2454. validPrimitive = true;
  2455. break;
  2456. case CSSPropertyWebkitLineBoxContain:
  2457. if (id == CSSValueNone)
  2458. validPrimitive = true;
  2459. else
  2460. return parseLineBoxContain(important);
  2461. break;
  2462. case CSSPropertyWebkitFontFeatureSettings:
  2463. if (id == CSSValueNormal)
  2464. validPrimitive = true;
  2465. else
  2466. return parseFontFeatureSettings(important);
  2467. break;
  2468. case CSSPropertyWebkitFontVariantLigatures:
  2469. if (id == CSSValueNormal)
  2470. validPrimitive = true;
  2471. else
  2472. return parseFontVariantLigatures(important);
  2473. break;
  2474. #if ENABLE(CSS_EXCLUSIONS)
  2475. case CSSPropertyWebkitShapeInside:
  2476. case CSSPropertyWebkitShapeOutside:
  2477. if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
  2478. return false;
  2479. if (id == CSSValueAuto)
  2480. validPrimitive = true;
  2481. else if (value->unit == CSSParserValue::Function)
  2482. return parseExclusionShape((propId == CSSPropertyWebkitShapeInside), important);
  2483. break;
  2484. case CSSPropertyWebkitWrapMargin:
  2485. case CSSPropertyWebkitWrapPadding:
  2486. validPrimitive = (RuntimeEnabledFeatures::cssExclusionsEnabled() && !id && validUnit(value, FLength | FNonNeg));
  2487. break;
  2488. case CSSPropertyWebkitWrap:
  2489. return RuntimeEnabledFeatures::cssExclusionsEnabled() && parseShorthand(propId, webkitWrapShorthand(), important);
  2490. #endif
  2491. #if ENABLE(CSS_IMAGE_ORIENTATION)
  2492. case CSSPropertyImageOrientation:
  2493. validPrimitive = !id && validUnit(value, FAngle);
  2494. break;
  2495. #endif
  2496. #if ENABLE(CSS_IMAGE_RESOLUTION)
  2497. case CSSPropertyImageResolution:
  2498. parsedValue = parseImageResolution(m_valueList.get());
  2499. if (!parsedValue)
  2500. return false;
  2501. m_valueList->next();
  2502. break;
  2503. #endif
  2504. case CSSPropertyBorderBottomStyle:
  2505. case CSSPropertyBorderCollapse:
  2506. case CSSPropertyBorderLeftStyle:
  2507. case CSSPropertyBorderRightStyle:
  2508. case CSSPropertyBorderTopStyle:
  2509. case CSSPropertyBoxSizing:
  2510. case CSSPropertyCaptionSide:
  2511. case CSSPropertyClear:
  2512. case CSSPropertyDirection:
  2513. case CSSPropertyDisplay:
  2514. case CSSPropertyEmptyCells:
  2515. case CSSPropertyFloat:
  2516. case CSSPropertyFontStyle:
  2517. case CSSPropertyImageRendering:
  2518. case CSSPropertyListStylePosition:
  2519. case CSSPropertyListStyleType:
  2520. case CSSPropertyOutlineStyle:
  2521. case CSSPropertyOverflowX:
  2522. case CSSPropertyOverflowY:
  2523. case CSSPropertyPageBreakAfter:
  2524. case CSSPropertyPageBreakBefore:
  2525. case CSSPropertyPageBreakInside:
  2526. case CSSPropertyPointerEvents:
  2527. case CSSPropertyPosition:
  2528. case CSSPropertyResize:
  2529. case CSSPropertySpeak:
  2530. case CSSPropertyTableLayout:
  2531. case CSSPropertyTextLineThroughMode:
  2532. case CSSPropertyTextLineThroughStyle:
  2533. case CSSPropertyTextOverflow:
  2534. case CSSPropertyTextOverlineMode:
  2535. case CSSPropertyTextOverlineStyle:
  2536. case CSSPropertyTextRendering:
  2537. case CSSPropertyTextTransform:
  2538. case CSSPropertyTextUnderlineMode:
  2539. case CSSPropertyTextUnderlineStyle:
  2540. #if ENABLE(CSS_VARIABLES)
  2541. case CSSPropertyVariable:
  2542. #endif
  2543. case CSSPropertyVisibility:
  2544. case CSSPropertyWebkitAppearance:
  2545. case CSSPropertyWebkitBackfaceVisibility:
  2546. case CSSPropertyWebkitBorderAfterStyle:
  2547. case CSSPropertyWebkitBorderBeforeStyle:
  2548. case CSSPropertyWebkitBorderEndStyle:
  2549. case CSSPropertyWebkitBorderFit:
  2550. case CSSPropertyWebkitBorderStartStyle:
  2551. case CSSPropertyWebkitBoxAlign:
  2552. #if ENABLE(CSS_BOX_DECORATION_BREAK)
  2553. case CSSPropertyWebkitBoxDecorationBreak:
  2554. #endif
  2555. case CSSPropertyWebkitBoxDirection:
  2556. case CSSPropertyWebkitBoxLines:
  2557. case CSSPropertyWebkitBoxOrient:
  2558. case CSSPropertyWebkitBoxPack:
  2559. case CSSPropertyWebkitColorCorrection:
  2560. case CSSPropertyWebkitColumnBreakAfter:
  2561. case CSSPropertyWebkitColumnBreakBefore:
  2562. case CSSPropertyWebkitColumnBreakInside:
  2563. case CSSPropertyWebkitColumnRuleStyle:
  2564. #if ENABLE(CSS3_FLEXBOX)
  2565. case CSSPropertyWebkitAlignContent:
  2566. case CSSPropertyWebkitAlignItems:
  2567. case CSSPropertyWebkitAlignSelf:
  2568. case CSSPropertyWebkitFlexDirection:
  2569. case CSSPropertyWebkitFlexWrap:
  2570. case CSSPropertyWebkitJustifyContent:
  2571. #endif
  2572. case CSSPropertyWebkitFontKerning:
  2573. case CSSPropertyWebkitFontSmoothing:
  2574. case CSSPropertyWebkitHyphens:
  2575. case CSSPropertyWebkitLineAlign:
  2576. case CSSPropertyWebkitLineBreak:
  2577. case CSSPropertyWebkitLineSnap:
  2578. case CSSPropertyWebkitMarginAfterCollapse:
  2579. case CSSPropertyWebkitMarginBeforeCollapse:
  2580. case CSSPropertyWebkitMarginBottomCollapse:
  2581. case CSSPropertyWebkitMarginTopCollapse:
  2582. case CSSPropertyWebkitMarqueeDirection:
  2583. case CSSPropertyWebkitMarqueeStyle:
  2584. case CSSPropertyWebkitNbspMode:
  2585. #if ENABLE(OVERFLOW_SCROLLING)
  2586. case CSSPropertyWebkitOverflowScrolling:
  2587. #endif
  2588. case CSSPropertyWebkitPrintColorAdjust:
  2589. #if ENABLE(CSS_REGIONS)
  2590. case CSSPropertyWebkitRegionBreakAfter:
  2591. case CSSPropertyWebkitRegionBreakBefore:
  2592. case CSSPropertyWebkitRegionBreakInside:
  2593. case CSSPropertyWebkitRegionOverflow:
  2594. #endif
  2595. case CSSPropertyWebkitRtlOrdering:
  2596. case CSSPropertyWebkitTextCombine:
  2597. case CSSPropertyWebkitTextEmphasisPosition:
  2598. case CSSPropertyWebkitTextSecurity:
  2599. case CSSPropertyWebkitTextSizeAdjust:
  2600. case CSSPropertyWebkitTransformStyle:
  2601. case CSSPropertyWebkitUserDrag:
  2602. case CSSPropertyWebkitUserModify:
  2603. case CSSPropertyWebkitUserSelect:
  2604. #if ENABLE(CSS_EXCLUSIONS)
  2605. case CSSPropertyWebkitWrapFlow:
  2606. case CSSPropertyWebkitWrapThrough:
  2607. #endif
  2608. case CSSPropertyWebkitWritingMode:
  2609. case CSSPropertyWhiteSpace:
  2610. case CSSPropertyWordBreak:
  2611. case CSSPropertyWordWrap:
  2612. // These properties should be handled before in isValidKeywordPropertyAndValue().
  2613. ASSERT_NOT_REACHED();
  2614. return false;
  2615. #if ENABLE(SVG)
  2616. default:
  2617. return parseSVGValue(propId, important);
  2618. #endif
  2619. }
  2620. if (validPrimitive) {
  2621. parsedValue = parseValidPrimitive(id, value);
  2622. m_valueList->next();
  2623. }
  2624. ASSERT(!m_parsedCalculation);
  2625. if (parsedValue) {
  2626. if (!m_valueList->current() || inShorthand()) {
  2627. addProperty(propId, parsedValue.release(), important);
  2628. return true;
  2629. }
  2630. }
  2631. return false;
  2632. }
  2633. void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
  2634. {
  2635. if (lval) {
  2636. if (lval->isValueList())
  2637. static_cast<CSSValueList*>(lval.get())->append(rval);
  2638. else {
  2639. PassRefPtr<CSSValue> oldlVal(lval.release());
  2640. PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
  2641. list->append(oldlVal);
  2642. list->append(rval);
  2643. lval = list;
  2644. }
  2645. }
  2646. else
  2647. lval = rval;
  2648. }
  2649. static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue)
  2650. {
  2651. if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
  2652. || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
  2653. cssValue = cssValuePool().createIdentifierValue(parserValue->id);
  2654. return true;
  2655. }
  2656. return false;
  2657. }
  2658. const int cMaxFillProperties = 9;
  2659. bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
  2660. {
  2661. ASSERT(numProperties <= cMaxFillProperties);
  2662. if (numProperties > cMaxFillProperties)
  2663. return false;
  2664. ShorthandScope scope(this, propId);
  2665. bool parsedProperty[cMaxFillProperties] = { false };
  2666. RefPtr<CSSValue> values[cMaxFillProperties];
  2667. RefPtr<CSSValue> clipValue;
  2668. RefPtr<CSSValue> positionYValue;
  2669. RefPtr<CSSValue> repeatYValue;
  2670. bool foundClip = false;
  2671. int i;
  2672. bool foundBackgroundPositionCSSProperty = false;
  2673. while (m_valueList->current()) {
  2674. CSSParserValue* val = m_valueList->current();
  2675. if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
  2676. // We hit the end. Fill in all remaining values with the initial value.
  2677. m_valueList->next();
  2678. for (i = 0; i < numProperties; ++i) {
  2679. if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
  2680. // Color is not allowed except as the last item in a list for backgrounds.
  2681. // Reject the entire property.
  2682. return false;
  2683. if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
  2684. addFillValue(values[i], cssValuePool().createImplicitInitialValue());
  2685. if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
  2686. addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
  2687. if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
  2688. addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
  2689. if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
  2690. // If background-origin wasn't present, then reset background-clip also.
  2691. addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
  2692. }
  2693. }
  2694. parsedProperty[i] = false;
  2695. }
  2696. if (!m_valueList->current())
  2697. break;
  2698. }
  2699. bool backgroundSizeCSSPropertyExpected = false;
  2700. if ((val->unit == CSSParserValue::Operator && val->iValue == '/') && foundBackgroundPositionCSSProperty) {
  2701. backgroundSizeCSSPropertyExpected = true;
  2702. m_valueList->next();
  2703. }
  2704. foundBackgroundPositionCSSProperty = false;
  2705. bool found = false;
  2706. for (i = 0; !found && i < numProperties; ++i) {
  2707. if (backgroundSizeCSSPropertyExpected && properties[i] != CSSPropertyBackgroundSize)
  2708. continue;
  2709. if (!backgroundSizeCSSPropertyExpected && properties[i] == CSSPropertyBackgroundSize)
  2710. continue;
  2711. if (!parsedProperty[i]) {
  2712. RefPtr<CSSValue> val1;
  2713. RefPtr<CSSValue> val2;
  2714. CSSPropertyID propId1, propId2;
  2715. CSSParserValue* parserValue = m_valueList->current();
  2716. if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
  2717. parsedProperty[i] = found = true;
  2718. addFillValue(values[i], val1.release());
  2719. if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
  2720. addFillValue(positionYValue, val2.release());
  2721. if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
  2722. addFillValue(repeatYValue, val2.release());
  2723. if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
  2724. // Reparse the value as a clip, and see if we succeed.
  2725. if (parseBackgroundClip(parserValue, val1))
  2726. addFillValue(clipValue, val1.release()); // The property parsed successfully.
  2727. else
  2728. addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
  2729. }
  2730. if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
  2731. // Update clipValue
  2732. addFillValue(clipValue, val1.release());
  2733. foundClip = true;
  2734. }
  2735. if (properties[i] == CSSPropertyBackgroundPosition)
  2736. foundBackgroundPositionCSSProperty = true;
  2737. }
  2738. }
  2739. }
  2740. // if we didn't find at least one match, this is an
  2741. // invalid shorthand and we have to ignore it
  2742. if (!found)
  2743. return false;
  2744. }
  2745. // Now add all of the properties we found.
  2746. for (i = 0; i < numProperties; i++) {
  2747. // Fill in any remaining properties with the initial value.
  2748. if (!parsedProperty[i]) {
  2749. addFillValue(values[i], cssValuePool().createImplicitInitialValue());
  2750. if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
  2751. addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
  2752. if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
  2753. addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
  2754. if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin)) {
  2755. // If background-origin wasn't present, then reset background-clip also.
  2756. addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
  2757. }
  2758. }
  2759. if (properties[i] == CSSPropertyBackgroundPosition) {
  2760. addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
  2761. // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
  2762. addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
  2763. } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
  2764. addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
  2765. // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
  2766. addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
  2767. } else if (properties[i] == CSSPropertyBackgroundRepeat) {
  2768. addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
  2769. // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
  2770. addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
  2771. } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
  2772. addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
  2773. // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
  2774. addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
  2775. } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
  2776. // Value is already set while updating origin
  2777. continue;
  2778. else
  2779. addProperty(properties[i], values[i].release(), important);
  2780. // Add in clip values when we hit the corresponding origin property.
  2781. if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
  2782. addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
  2783. else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
  2784. addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
  2785. }
  2786. return true;
  2787. }
  2788. #if ENABLE(CSS_VARIABLES)
  2789. bool CSSParser::cssVariablesEnabled() const
  2790. {
  2791. return m_context.isCSSVariablesEnabled;
  2792. }
  2793. void CSSParser::storeVariableDeclaration(const CSSParserString& name, PassOwnPtr<CSSParserValueList> value, bool important)
  2794. {
  2795. ASSERT(name.length > 12);
  2796. AtomicString variableName = String(name.characters + 12, name.length - 12);
  2797. StringBuilder builder;
  2798. for (unsigned i = 0, size = value->size(); i < size; i++) {
  2799. if (i)
  2800. builder.append(' ');
  2801. builder.append(value->valueAt(i)->createCSSValue()->cssText());
  2802. }
  2803. addProperty(CSSPropertyVariable, CSSVariableValue::create(variableName, builder.toString()), important, false);
  2804. }
  2805. #endif
  2806. void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
  2807. {
  2808. if (lval) {
  2809. if (lval->isValueList())
  2810. static_cast<CSSValueList*>(lval.get())->append(rval);
  2811. else {
  2812. PassRefPtr<CSSValue> oldVal(lval.release());
  2813. PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
  2814. list->append(oldVal);
  2815. list->append(rval);
  2816. lval = list;
  2817. }
  2818. }
  2819. else
  2820. lval = rval;
  2821. }
  2822. bool CSSParser::parseAnimationShorthand(bool important)
  2823. {
  2824. // When we parse the animation shorthand we need to look for animation-name
  2825. // last because otherwise it might match against the keywords for fill mode,
  2826. // timing functions and infinite iteration. This means that animation names
  2827. // that are the same as keywords (e.g. 'forwards') won't always match in the
  2828. // shorthand. In that case they should be using longhands (or reconsidering
  2829. // their approach). This is covered by the animations spec bug:
  2830. // https://www.w3.org/Bugs/Public/show_bug.cgi?id=14790
  2831. // And in the spec (editor's draft) at:
  2832. // http://dev.w3.org/csswg/css3-animations/#animation-shorthand-property
  2833. static const CSSPropertyID animationProperties[] = {
  2834. CSSPropertyWebkitAnimationDuration,
  2835. CSSPropertyWebkitAnimationTimingFunction,
  2836. CSSPropertyWebkitAnimationDelay,
  2837. CSSPropertyWebkitAnimationIterationCount,
  2838. CSSPropertyWebkitAnimationDirection,
  2839. CSSPropertyWebkitAnimationFillMode,
  2840. CSSPropertyWebkitAnimationName
  2841. };
  2842. const unsigned numProperties = 7;
  2843. // The list of properties in the shorthand should be the same
  2844. // length as the list we have here, even though they are
  2845. // a different order.
  2846. ASSERT(numProperties == webkitAnimationShorthand().length());
  2847. ShorthandScope scope(this, CSSPropertyWebkitAnimation);
  2848. bool parsedProperty[numProperties] = { false };
  2849. RefPtr<CSSValue> values[numProperties];
  2850. unsigned i;
  2851. while (m_valueList->current()) {
  2852. CSSParserValue* val = m_valueList->current();
  2853. if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
  2854. // We hit the end. Fill in all remaining values with the initial value.
  2855. m_valueList->next();
  2856. for (i = 0; i < numProperties; ++i) {
  2857. if (!parsedProperty[i])
  2858. addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
  2859. parsedProperty[i] = false;
  2860. }
  2861. if (!m_valueList->current())
  2862. break;
  2863. }
  2864. bool found = false;
  2865. for (i = 0; i < numProperties; ++i) {
  2866. if (!parsedProperty[i]) {
  2867. RefPtr<CSSValue> val;
  2868. if (parseAnimationProperty(animationProperties[i], val)) {
  2869. parsedProperty[i] = found = true;
  2870. addAnimationValue(values[i], val.release());
  2871. break;
  2872. }
  2873. }
  2874. }
  2875. // if we didn't find at least one match, this is an
  2876. // invalid shorthand and we have to ignore it
  2877. if (!found)
  2878. return false;
  2879. }
  2880. for (i = 0; i < numProperties; ++i) {
  2881. // If we didn't find the property, set an intial value.
  2882. if (!parsedProperty[i])
  2883. addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
  2884. addProperty(animationProperties[i], values[i].release(), important);
  2885. }
  2886. return true;
  2887. }
  2888. bool CSSParser::parseTransitionShorthand(bool important)
  2889. {
  2890. const unsigned numProperties = webkitTransitionShorthand().length();
  2891. ShorthandScope scope(this, CSSPropertyWebkitTransition);
  2892. bool parsedProperty[] = { false, false, false, false };
  2893. RefPtr<CSSValue> values[4];
  2894. unsigned i;
  2895. while (m_valueList->current()) {
  2896. CSSParserValue* val = m_valueList->current();
  2897. if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
  2898. // We hit the end. Fill in all remaining values with the initial value.
  2899. m_valueList->next();
  2900. for (i = 0; i < numProperties; ++i) {
  2901. if (!parsedProperty[i])
  2902. addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
  2903. parsedProperty[i] = false;
  2904. }
  2905. if (!m_valueList->current())
  2906. break;
  2907. }
  2908. bool found = false;
  2909. for (i = 0; !found && i < numProperties; ++i) {
  2910. if (!parsedProperty[i]) {
  2911. RefPtr<CSSValue> val;
  2912. if (parseAnimationProperty(webkitTransitionShorthand().properties()[i], val)) {
  2913. parsedProperty[i] = found = true;
  2914. addAnimationValue(values[i], val.release());
  2915. }
  2916. }
  2917. }
  2918. // if we didn't find at least one match, this is an
  2919. // invalid shorthand and we have to ignore it
  2920. if (!found)
  2921. return false;
  2922. }
  2923. // Fill in any remaining properties with the initial value.
  2924. for (i = 0; i < numProperties; ++i) {
  2925. if (!parsedProperty[i])
  2926. addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
  2927. }
  2928. // Now add all of the properties we found.
  2929. for (i = 0; i < numProperties; i++)
  2930. addProperty(webkitTransitionShorthand().properties()[i], values[i].release(), important);
  2931. return true;
  2932. }
  2933. bool CSSParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
  2934. {
  2935. // We try to match as many properties as possible
  2936. // We set up an array of booleans to mark which property has been found,
  2937. // and we try to search for properties until it makes no longer any sense.
  2938. ShorthandScope scope(this, propId);
  2939. bool found = false;
  2940. unsigned propertiesParsed = 0;
  2941. bool propertyFound[6]= { false, false, false, false, false, false }; // 6 is enough size.
  2942. while (m_valueList->current()) {
  2943. found = false;
  2944. for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
  2945. if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
  2946. propertyFound[propIndex] = found = true;
  2947. propertiesParsed++;
  2948. }
  2949. }
  2950. // if we didn't find at least one match, this is an
  2951. // invalid shorthand and we have to ignore it
  2952. if (!found)
  2953. return false;
  2954. }
  2955. if (propertiesParsed == shorthand.length())
  2956. return true;
  2957. // Fill in any remaining properties with the initial value.
  2958. ImplicitScope implicitScope(this, PropertyImplicit);
  2959. const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization();
  2960. for (unsigned i = 0; i < shorthand.length(); ++i) {
  2961. if (propertyFound[i])
  2962. continue;
  2963. if (propertiesForInitialization) {
  2964. const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]);
  2965. for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
  2966. addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
  2967. } else
  2968. addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
  2969. }
  2970. return true;
  2971. }
  2972. bool CSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties, bool important)
  2973. {
  2974. /* From the CSS 2 specs, 8.3
  2975. * If there is only one value, it applies to all sides. If there are two values, the top and
  2976. * bottom margins are set to the first value and the right and left margins are set to the second.
  2977. * If there are three values, the top is set to the first value, the left and right are set to the
  2978. * second, and the bottom is set to the third. If there are four values, they apply to the top,
  2979. * right, bottom, and left, respectively.
  2980. */
  2981. int num = inShorthand() ? 1 : m_valueList->size();
  2982. ShorthandScope scope(this, propId);
  2983. // the order is top, right, bottom, left
  2984. switch (num) {
  2985. case 1: {
  2986. if (!parseValue(properties[0], important))
  2987. return false;
  2988. CSSValue *value = m_parsedProperties.last().value();
  2989. ImplicitScope implicitScope(this, PropertyImplicit);
  2990. addProperty(properties[1], value, important);
  2991. addProperty(properties[2], value, important);
  2992. addProperty(properties[3], value, important);
  2993. break;
  2994. }
  2995. case 2: {
  2996. if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
  2997. return false;
  2998. CSSValue *value = m_parsedProperties[m_parsedProperties.size() - 2].value();
  2999. ImplicitScope implicitScope(this, PropertyImplicit);
  3000. addProperty(properties[2], value, important);
  3001. value = m_parsedProperties[m_parsedProperties.size() - 2].value();
  3002. addProperty(properties[3], value, important);
  3003. break;
  3004. }
  3005. case 3: {
  3006. if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
  3007. return false;
  3008. CSSValue *value = m_parsedProperties[m_parsedProperties.size() - 2].value();
  3009. ImplicitScope implicitScope(this, PropertyImplicit);
  3010. addProperty(properties[3], value, important);
  3011. break;
  3012. }
  3013. case 4: {
  3014. if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
  3015. !parseValue(properties[2], important) || !parseValue(properties[3], important))
  3016. return false;
  3017. break;
  3018. }
  3019. default: {
  3020. return false;
  3021. }
  3022. }
  3023. return true;
  3024. }
  3025. // auto | <identifier>
  3026. bool CSSParser::parsePage(CSSPropertyID propId, bool important)
  3027. {
  3028. ASSERT(propId == CSSPropertyPage);
  3029. if (m_valueList->size() != 1)
  3030. return false;
  3031. CSSParserValue* value = m_valueList->current();
  3032. if (!value)
  3033. return false;
  3034. if (value->id == CSSValueAuto) {
  3035. addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
  3036. return true;
  3037. } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
  3038. addProperty(propId, createPrimitiveStringValue(value), important);
  3039. return true;
  3040. }
  3041. return false;
  3042. }
  3043. // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
  3044. bool CSSParser::parseSize(CSSPropertyID propId, bool important)
  3045. {
  3046. ASSERT(propId == CSSPropertySize);
  3047. if (m_valueList->size() > 2)
  3048. return false;
  3049. CSSParserValue* value = m_valueList->current();
  3050. if (!value)
  3051. return false;
  3052. RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
  3053. // First parameter.
  3054. SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
  3055. if (paramType == None)
  3056. return false;
  3057. // Second parameter, if any.
  3058. value = m_valueList->next();
  3059. if (value) {
  3060. paramType = parseSizeParameter(parsedValues.get(), value, paramType);
  3061. if (paramType == None)
  3062. return false;
  3063. }
  3064. addProperty(propId, parsedValues.release(), important);
  3065. return true;
  3066. }
  3067. CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
  3068. {
  3069. switch (value->id) {
  3070. case CSSValueAuto:
  3071. if (prevParamType == None) {
  3072. parsedValues->append(cssValuePool().createIdentifierValue(value->id));
  3073. return Auto;
  3074. }
  3075. return None;
  3076. case CSSValueLandscape:
  3077. case CSSValuePortrait:
  3078. if (prevParamType == None || prevParamType == PageSize) {
  3079. parsedValues->append(cssValuePool().createIdentifierValue(value->id));
  3080. return Orientation;
  3081. }
  3082. return None;
  3083. case CSSValueA3:
  3084. case CSSValueA4:
  3085. case CSSValueA5:
  3086. case CSSValueB4:
  3087. case CSSValueB5:
  3088. case CSSValueLedger:
  3089. case CSSValueLegal:
  3090. case CSSValueLetter:
  3091. if (prevParamType == None || prevParamType == Orientation) {
  3092. // Normalize to Page Size then Orientation order by prepending.
  3093. // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
  3094. parsedValues->prepend(cssValuePool().createIdentifierValue(value->id));
  3095. return PageSize;
  3096. }
  3097. return None;
  3098. case 0:
  3099. if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) {
  3100. parsedValues->append(createPrimitiveNumericValue(value));
  3101. return Length;
  3102. }
  3103. return None;
  3104. default:
  3105. return None;
  3106. }
  3107. }
  3108. // [ <string> <string> ]+ | inherit | none
  3109. // inherit and none are handled in parseValue.
  3110. bool CSSParser::parseQuotes(CSSPropertyID propId, bool important)
  3111. {
  3112. RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
  3113. while (CSSParserValue* val = m_valueList->current()) {
  3114. RefPtr<CSSValue> parsedValue;
  3115. if (val->unit == CSSPrimitiveValue::CSS_STRING)
  3116. parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
  3117. else
  3118. break;
  3119. values->append(parsedValue.release());
  3120. m_valueList->next();
  3121. }
  3122. if (values->length()) {
  3123. addProperty(propId, values.release(), important);
  3124. m_valueList->next();
  3125. return true;
  3126. }
  3127. return false;
  3128. }
  3129. // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
  3130. // in CSS 2.1 this got somewhat reduced:
  3131. // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
  3132. bool CSSParser::parseContent(CSSPropertyID propId, bool important)
  3133. {
  3134. RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
  3135. while (CSSParserValue* val = m_valueList->current()) {
  3136. RefPtr<CSSValue> parsedValue;
  3137. if (val->unit == CSSPrimitiveValue::CSS_URI) {
  3138. // url
  3139. parsedValue = CSSImageValue::create(completeURL(val->string));
  3140. } else if (val->unit == CSSParserValue::Function) {
  3141. // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
  3142. CSSParserValueList* args = val->function->args.get();
  3143. if (!args)
  3144. return false;
  3145. if (equalIgnoringCase(val->function->name, "attr(")) {
  3146. parsedValue = parseAttr(args);
  3147. if (!parsedValue)
  3148. return false;
  3149. } else if (equalIgnoringCase(val->function->name, "counter(")) {
  3150. parsedValue = parseCounterContent(args, false);
  3151. if (!parsedValue)
  3152. return false;
  3153. } else if (equalIgnoringCase(val->function->name, "counters(")) {
  3154. parsedValue = parseCounterContent(args, true);
  3155. if (!parsedValue)
  3156. return false;
  3157. #if ENABLE(CSS_IMAGE_SET)
  3158. } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
  3159. parsedValue = parseImageSet(m_valueList.get());
  3160. if (!parsedValue)
  3161. return false;
  3162. #endif
  3163. } else if (isGeneratedImageValue(val)) {
  3164. if (!parseGeneratedImage(m_valueList.get(), parsedValue))
  3165. return false;
  3166. } else
  3167. return false;
  3168. } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
  3169. // open-quote
  3170. // close-quote
  3171. // no-open-quote
  3172. // no-close-quote
  3173. // inherit
  3174. // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
  3175. // none
  3176. // normal
  3177. switch (val->id) {
  3178. case CSSValueOpenQuote:
  3179. case CSSValueCloseQuote:
  3180. case CSSValueNoOpenQuote:
  3181. case CSSValueNoCloseQuote:
  3182. case CSSValueNone:
  3183. case CSSValueNormal:
  3184. parsedValue = cssValuePool().createIdentifierValue(val->id);
  3185. }
  3186. } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
  3187. parsedValue = createPrimitiveStringValue(val);
  3188. }
  3189. if (!parsedValue)
  3190. break;
  3191. values->append(parsedValue.release());
  3192. m_valueList->next();
  3193. }
  3194. if (values->length()) {
  3195. addProperty(propId, values.release(), important);
  3196. m_valueList->next();
  3197. return true;
  3198. }
  3199. return false;
  3200. }
  3201. PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args)
  3202. {
  3203. if (args->size() != 1)
  3204. return 0;
  3205. CSSParserValue* a = args->current();
  3206. if (a->unit != CSSPrimitiveValue::CSS_IDENT)
  3207. return 0;
  3208. String attrName = a->string;
  3209. // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
  3210. // But HTML attribute names can't have those characters, and we should not
  3211. // even parse them inside attr().
  3212. if (attrName[0] == '-')
  3213. return 0;
  3214. if (m_context.isHTMLDocument)
  3215. attrName = attrName.lower();
  3216. return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
  3217. }
  3218. PassRefPtr<CSSValue> CSSParser::parseBackgroundColor()
  3219. {
  3220. int id = m_valueList->current()->id;
  3221. if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
  3222. (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
  3223. return cssValuePool().createIdentifierValue(id);
  3224. return parseColor();
  3225. }
  3226. bool CSSParser::parseFillImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
  3227. {
  3228. if (valueList->current()->id == CSSValueNone) {
  3229. value = cssValuePool().createIdentifierValue(CSSValueNone);
  3230. return true;
  3231. }
  3232. if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
  3233. value = CSSImageValue::create(completeURL(valueList->current()->string));
  3234. return true;
  3235. }
  3236. if (isGeneratedImageValue(valueList->current()))
  3237. return parseGeneratedImage(valueList, value);
  3238. #if ENABLE(CSS_IMAGE_SET)
  3239. if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) {
  3240. value = parseImageSet(m_valueList.get());
  3241. if (value)
  3242. return true;
  3243. }
  3244. #endif
  3245. return false;
  3246. }
  3247. PassRefPtr<CSSValue> CSSParser::parseFillPositionX(CSSParserValueList* valueList)
  3248. {
  3249. int id = valueList->current()->id;
  3250. if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
  3251. int percent = 0;
  3252. if (id == CSSValueRight)
  3253. percent = 100;
  3254. else if (id == CSSValueCenter)
  3255. percent = 50;
  3256. return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
  3257. }
  3258. if (validUnit(valueList->current(), FPercent | FLength))
  3259. return createPrimitiveNumericValue(valueList->current());
  3260. return 0;
  3261. }
  3262. PassRefPtr<CSSValue> CSSParser::parseFillPositionY(CSSParserValueList* valueList)
  3263. {
  3264. int id = valueList->current()->id;
  3265. if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
  3266. int percent = 0;
  3267. if (id == CSSValueBottom)
  3268. percent = 100;
  3269. else if (id == CSSValueCenter)
  3270. percent = 50;
  3271. return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
  3272. }
  3273. if (validUnit(valueList->current(), FPercent | FLength))
  3274. return createPrimitiveNumericValue(valueList->current());
  3275. return 0;
  3276. }
  3277. PassRefPtr<CSSValue> CSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag)
  3278. {
  3279. int id = valueList->current()->id;
  3280. if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
  3281. int percent = 0;
  3282. if (id == CSSValueLeft || id == CSSValueRight) {
  3283. if (cumulativeFlags & XFillPosition)
  3284. return 0;
  3285. cumulativeFlags |= XFillPosition;
  3286. individualFlag = XFillPosition;
  3287. if (id == CSSValueRight)
  3288. percent = 100;
  3289. }
  3290. else if (id == CSSValueTop || id == CSSValueBottom) {
  3291. if (cumulativeFlags & YFillPosition)
  3292. return 0;
  3293. cumulativeFlags |= YFillPosition;
  3294. individualFlag = YFillPosition;
  3295. if (id == CSSValueBottom)
  3296. percent = 100;
  3297. } else if (id == CSSValueCenter) {
  3298. // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
  3299. percent = 50;
  3300. cumulativeFlags |= AmbiguousFillPosition;
  3301. individualFlag = AmbiguousFillPosition;
  3302. }
  3303. return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
  3304. }
  3305. if (validUnit(valueList->current(), FPercent | FLength)) {
  3306. if (!cumulativeFlags) {
  3307. cumulativeFlags |= XFillPosition;
  3308. individualFlag = XFillPosition;
  3309. } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
  3310. cumulativeFlags |= YFillPosition;
  3311. individualFlag = YFillPosition;
  3312. } else {
  3313. if (m_parsedCalculation)
  3314. m_parsedCalculation.release();
  3315. return 0;
  3316. }
  3317. return createPrimitiveNumericValue(valueList->current());
  3318. }
  3319. return 0;
  3320. }
  3321. void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
  3322. {
  3323. CSSParserValue* value = valueList->current();
  3324. // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
  3325. unsigned cumulativeFlags = 0;
  3326. FillPositionFlag value1Flag = InvalidFillPosition;
  3327. FillPositionFlag value2Flag = InvalidFillPosition;
  3328. value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
  3329. if (!value1)
  3330. return;
  3331. // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
  3332. // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the
  3333. // value was explicitly specified for our property.
  3334. value = valueList->next();
  3335. // First check for the comma. If so, we are finished parsing this value or value pair.
  3336. if (isComma(value))
  3337. value = 0;
  3338. if (value) {
  3339. value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
  3340. if (value2)
  3341. valueList->next();
  3342. else {
  3343. if (!inShorthand()) {
  3344. value1.clear();
  3345. return;
  3346. }
  3347. }
  3348. }
  3349. if (!value2)
  3350. // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
  3351. // is simply 50%. This is our default.
  3352. // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
  3353. // For left/right/center, the default of 50% in the y is still correct.
  3354. value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
  3355. if (value1Flag == YFillPosition || value2Flag == XFillPosition)
  3356. value1.swap(value2);
  3357. }
  3358. void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
  3359. {
  3360. int id = m_valueList->current()->id;
  3361. if (id == CSSValueRepeatX) {
  3362. m_implicitShorthand = true;
  3363. value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
  3364. value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
  3365. m_valueList->next();
  3366. return;
  3367. }
  3368. if (id == CSSValueRepeatY) {
  3369. m_implicitShorthand = true;
  3370. value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
  3371. value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
  3372. m_valueList->next();
  3373. return;
  3374. }
  3375. if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
  3376. value1 = cssValuePool().createIdentifierValue(id);
  3377. else {
  3378. value1 = 0;
  3379. return;
  3380. }
  3381. CSSParserValue* value = m_valueList->next();
  3382. // Parse the second value if one is available
  3383. if (value && !isComma(value)) {
  3384. id = value->id;
  3385. if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
  3386. value2 = cssValuePool().createIdentifierValue(id);
  3387. m_valueList->next();
  3388. return;
  3389. }
  3390. }
  3391. // If only one value was specified, value2 is the same as value1.
  3392. m_implicitShorthand = true;
  3393. value2 = cssValuePool().createIdentifierValue(static_cast<CSSPrimitiveValue*>(value1.get())->getIdent());
  3394. }
  3395. PassRefPtr<CSSValue> CSSParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
  3396. {
  3397. allowComma = true;
  3398. CSSParserValue* value = m_valueList->current();
  3399. if (value->id == CSSValueContain || value->id == CSSValueCover)
  3400. return cssValuePool().createIdentifierValue(value->id);
  3401. RefPtr<CSSPrimitiveValue> parsedValue1;
  3402. if (value->id == CSSValueAuto)
  3403. parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
  3404. else {
  3405. if (!validUnit(value, FLength | FPercent))
  3406. return 0;
  3407. parsedValue1 = createPrimitiveNumericValue(value);
  3408. }
  3409. RefPtr<CSSPrimitiveValue> parsedValue2;
  3410. if ((value = m_valueList->next())) {
  3411. if (value->unit == CSSParserValue::Operator && value->iValue == ',')
  3412. allowComma = false;
  3413. else if (value->id != CSSValueAuto) {
  3414. if (!validUnit(value, FLength | FPercent)) {
  3415. if (!inShorthand())
  3416. return 0;
  3417. // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
  3418. m_valueList->previous();
  3419. } else
  3420. parsedValue2 = createPrimitiveNumericValue(value);
  3421. }
  3422. } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
  3423. // For backwards compatibility we set the second value to the first if it is omitted.
  3424. // We only need to do this for -webkit-background-size. It should be safe to let masks match
  3425. // the real property.
  3426. parsedValue2 = parsedValue1;
  3427. }
  3428. if (!parsedValue2)
  3429. return parsedValue1;
  3430. return cssValuePool().createValue(Pair::create(parsedValue1.release(), parsedValue2.release()));
  3431. }
  3432. bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
  3433. RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
  3434. {
  3435. RefPtr<CSSValueList> values;
  3436. RefPtr<CSSValueList> values2;
  3437. CSSParserValue* val;
  3438. RefPtr<CSSValue> value;
  3439. RefPtr<CSSValue> value2;
  3440. bool allowComma = false;
  3441. retValue1 = retValue2 = 0;
  3442. propId1 = propId;
  3443. propId2 = propId;
  3444. if (propId == CSSPropertyBackgroundPosition) {
  3445. propId1 = CSSPropertyBackgroundPositionX;
  3446. propId2 = CSSPropertyBackgroundPositionY;
  3447. } else if (propId == CSSPropertyWebkitMaskPosition) {
  3448. propId1 = CSSPropertyWebkitMaskPositionX;
  3449. propId2 = CSSPropertyWebkitMaskPositionY;
  3450. } else if (propId == CSSPropertyBackgroundRepeat) {
  3451. propId1 = CSSPropertyBackgroundRepeatX;
  3452. propId2 = CSSPropertyBackgroundRepeatY;
  3453. } else if (propId == CSSPropertyWebkitMaskRepeat) {
  3454. propId1 = CSSPropertyWebkitMaskRepeatX;
  3455. propId2 = CSSPropertyWebkitMaskRepeatY;
  3456. }
  3457. while ((val = m_valueList->current())) {
  3458. RefPtr<CSSValue> currValue;
  3459. RefPtr<CSSValue> currValue2;
  3460. if (allowComma) {
  3461. if (!isComma(val))
  3462. return false;
  3463. m_valueList->next();
  3464. allowComma = false;
  3465. } else {
  3466. allowComma = true;
  3467. switch (propId) {
  3468. case CSSPropertyBackgroundColor:
  3469. currValue = parseBackgroundColor();
  3470. if (currValue)
  3471. m_valueList->next();
  3472. break;
  3473. case CSSPropertyBackgroundAttachment:
  3474. case CSSPropertyWebkitMaskAttachment:
  3475. if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
  3476. currValue = cssValuePool().createIdentifierValue(val->id);
  3477. m_valueList->next();
  3478. }
  3479. break;
  3480. case CSSPropertyBackgroundImage:
  3481. case CSSPropertyWebkitMaskImage:
  3482. if (parseFillImage(m_valueList.get(), currValue))
  3483. m_valueList->next();
  3484. break;
  3485. case CSSPropertyWebkitBackgroundClip:
  3486. case CSSPropertyWebkitBackgroundOrigin:
  3487. case CSSPropertyWebkitMaskClip:
  3488. case CSSPropertyWebkitMaskOrigin:
  3489. // The first three values here are deprecated and do not apply to the version of the property that has
  3490. // the -webkit- prefix removed.
  3491. if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
  3492. val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
  3493. ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
  3494. (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
  3495. currValue = cssValuePool().createIdentifierValue(val->id);
  3496. m_valueList->next();
  3497. }
  3498. break;
  3499. case CSSPropertyBackgroundClip:
  3500. if (parseBackgroundClip(val, currValue))
  3501. m_valueList->next();
  3502. break;
  3503. case CSSPropertyBackgroundOrigin:
  3504. if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
  3505. currValue = cssValuePool().createIdentifierValue(val->id);
  3506. m_valueList->next();
  3507. }
  3508. break;
  3509. case CSSPropertyBackgroundPosition:
  3510. case CSSPropertyWebkitMaskPosition:
  3511. parseFillPosition(m_valueList.get(), currValue, currValue2);
  3512. // parseFillPosition advances the m_valueList pointer
  3513. break;
  3514. case CSSPropertyBackgroundPositionX:
  3515. case CSSPropertyWebkitMaskPositionX: {
  3516. currValue = parseFillPositionX(m_valueList.get());
  3517. if (currValue)
  3518. m_valueList->next();
  3519. break;
  3520. }
  3521. case CSSPropertyBackgroundPositionY:
  3522. case CSSPropertyWebkitMaskPositionY: {
  3523. currValue = parseFillPositionY(m_valueList.get());
  3524. if (currValue)
  3525. m_valueList->next();
  3526. break;
  3527. }
  3528. case CSSPropertyWebkitBackgroundComposite:
  3529. case CSSPropertyWebkitMaskComposite:
  3530. if ((val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) || val->id == CSSValueHighlight) {
  3531. currValue = cssValuePool().createIdentifierValue(val->id);
  3532. m_valueList->next();
  3533. }
  3534. break;
  3535. case CSSPropertyBackgroundRepeat:
  3536. case CSSPropertyWebkitMaskRepeat:
  3537. parseFillRepeat(currValue, currValue2);
  3538. // parseFillRepeat advances the m_valueList pointer
  3539. break;
  3540. case CSSPropertyBackgroundSize:
  3541. case CSSPropertyWebkitBackgroundSize:
  3542. case CSSPropertyWebkitMaskSize: {
  3543. currValue = parseFillSize(propId, allowComma);
  3544. if (currValue)
  3545. m_valueList->next();
  3546. break;
  3547. }
  3548. default:
  3549. break;
  3550. }
  3551. if (!currValue)
  3552. return false;
  3553. if (value && !values) {
  3554. values = CSSValueList::createCommaSeparated();
  3555. values->append(value.release());
  3556. }
  3557. if (value2 && !values2) {
  3558. values2 = CSSValueList::createCommaSeparated();
  3559. values2->append(value2.release());
  3560. }
  3561. if (values)
  3562. values->append(currValue.release());
  3563. else
  3564. value = currValue.release();
  3565. if (currValue2) {
  3566. if (values2)
  3567. values2->append(currValue2.release());
  3568. else
  3569. value2 = currValue2.release();
  3570. }
  3571. }
  3572. // When parsing any fill shorthand property, we let it handle building up the lists for all
  3573. // properties.
  3574. if (inShorthand())
  3575. break;
  3576. }
  3577. if (values && values->length()) {
  3578. retValue1 = values.release();
  3579. if (values2 && values2->length())
  3580. retValue2 = values2.release();
  3581. return true;
  3582. }
  3583. if (value) {
  3584. retValue1 = value.release();
  3585. retValue2 = value2.release();
  3586. return true;
  3587. }
  3588. return false;
  3589. }
  3590. PassRefPtr<CSSValue> CSSParser::parseAnimationDelay()
  3591. {
  3592. CSSParserValue* value = m_valueList->current();
  3593. if (validUnit(value, FTime))
  3594. return createPrimitiveNumericValue(value);
  3595. return 0;
  3596. }
  3597. PassRefPtr<CSSValue> CSSParser::parseAnimationDirection()
  3598. {
  3599. CSSParserValue* value = m_valueList->current();
  3600. if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
  3601. return cssValuePool().createIdentifierValue(value->id);
  3602. return 0;
  3603. }
  3604. PassRefPtr<CSSValue> CSSParser::parseAnimationDuration()
  3605. {
  3606. CSSParserValue* value = m_valueList->current();
  3607. if (validUnit(value, FTime | FNonNeg))
  3608. return createPrimitiveNumericValue(value);
  3609. return 0;
  3610. }
  3611. PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode()
  3612. {
  3613. CSSParserValue* value = m_valueList->current();
  3614. if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
  3615. return cssValuePool().createIdentifierValue(value->id);
  3616. return 0;
  3617. }
  3618. PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount()
  3619. {
  3620. CSSParserValue* value = m_valueList->current();
  3621. if (value->id == CSSValueInfinite)
  3622. return cssValuePool().createIdentifierValue(value->id);
  3623. if (validUnit(value, FNumber | FNonNeg))
  3624. return createPrimitiveNumericValue(value);
  3625. return 0;
  3626. }
  3627. PassRefPtr<CSSValue> CSSParser::parseAnimationName()
  3628. {
  3629. CSSParserValue* value = m_valueList->current();
  3630. if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
  3631. if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value->string, "none"))) {
  3632. return cssValuePool().createIdentifierValue(CSSValueNone);
  3633. } else {
  3634. return createPrimitiveStringValue(value);
  3635. }
  3636. }
  3637. return 0;
  3638. }
  3639. PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState()
  3640. {
  3641. CSSParserValue* value = m_valueList->current();
  3642. if (value->id == CSSValueRunning || value->id == CSSValuePaused)
  3643. return cssValuePool().createIdentifierValue(value->id);
  3644. return 0;
  3645. }
  3646. PassRefPtr<CSSValue> CSSParser::parseAnimationProperty()
  3647. {
  3648. CSSParserValue* value = m_valueList->current();
  3649. if (value->unit != CSSPrimitiveValue::CSS_IDENT)
  3650. return 0;
  3651. int result = cssPropertyID(value->string);
  3652. if (result)
  3653. return cssValuePool().createIdentifierValue(result);
  3654. if (equalIgnoringCase(value->string, "all"))
  3655. return cssValuePool().createIdentifierValue(CSSValueAll);
  3656. if (equalIgnoringCase(value->string, "none"))
  3657. return cssValuePool().createIdentifierValue(CSSValueNone);
  3658. return 0;
  3659. }
  3660. bool CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
  3661. {
  3662. parseFillPosition(m_valueList.get(), value1, value2);
  3663. // now get z
  3664. if (m_valueList->current()) {
  3665. if (validUnit(m_valueList->current(), FLength)) {
  3666. value3 = createPrimitiveNumericValue(m_valueList->current());
  3667. m_valueList->next();
  3668. return true;
  3669. }
  3670. return false;
  3671. }
  3672. value3 = cssValuePool().createImplicitInitialValue();
  3673. return true;
  3674. }
  3675. bool CSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
  3676. {
  3677. CSSParserValue* v = args->current();
  3678. if (!validUnit(v, FNumber))
  3679. return false;
  3680. result = v->fValue;
  3681. v = args->next();
  3682. if (!v)
  3683. // The last number in the function has no comma after it, so we're done.
  3684. return true;
  3685. if (!isComma(v))
  3686. return false;
  3687. args->next();
  3688. return true;
  3689. }
  3690. PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction()
  3691. {
  3692. CSSParserValue* value = m_valueList->current();
  3693. if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
  3694. || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd)
  3695. return cssValuePool().createIdentifierValue(value->id);
  3696. // We must be a function.
  3697. if (value->unit != CSSParserValue::Function)
  3698. return 0;
  3699. CSSParserValueList* args = value->function->args.get();
  3700. if (equalIgnoringCase(value->function->name, "steps(")) {
  3701. // For steps, 1 or 2 params must be specified (comma-separated)
  3702. if (!args || (args->size() != 1 && args->size() != 3))
  3703. return 0;
  3704. // There are two values.
  3705. int numSteps;
  3706. bool stepAtStart = false;
  3707. CSSParserValue* v = args->current();
  3708. if (!validUnit(v, FInteger))
  3709. return 0;
  3710. numSteps = clampToInteger(v->fValue);
  3711. if (numSteps < 1)
  3712. return 0;
  3713. v = args->next();
  3714. if (v) {
  3715. // There is a comma so we need to parse the second value
  3716. if (!isComma(v))
  3717. return 0;
  3718. v = args->next();
  3719. if (v->id != CSSValueStart && v->id != CSSValueEnd)
  3720. return 0;
  3721. stepAtStart = v->id == CSSValueStart;
  3722. }
  3723. return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart);
  3724. }
  3725. if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
  3726. // For cubic bezier, 4 values must be specified.
  3727. if (!args || args->size() != 7)
  3728. return 0;
  3729. // There are two points specified. The values must be between 0 and 1.
  3730. double x1, y1, x2, y2;
  3731. if (!parseCubicBezierTimingFunctionValue(args, x1))
  3732. return 0;
  3733. if (!parseCubicBezierTimingFunctionValue(args, y1))
  3734. return 0;
  3735. if (!parseCubicBezierTimingFunctionValue(args, x2))
  3736. return 0;
  3737. if (!parseCubicBezierTimingFunctionValue(args, y2))
  3738. return 0;
  3739. return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
  3740. }
  3741. return 0;
  3742. }
  3743. bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& result)
  3744. {
  3745. RefPtr<CSSValueList> values;
  3746. CSSParserValue* val;
  3747. RefPtr<CSSValue> value;
  3748. bool allowComma = false;
  3749. result = 0;
  3750. while ((val = m_valueList->current())) {
  3751. RefPtr<CSSValue> currValue;
  3752. if (allowComma) {
  3753. if (!isComma(val))
  3754. return false;
  3755. m_valueList->next();
  3756. allowComma = false;
  3757. }
  3758. else {
  3759. switch (propId) {
  3760. case CSSPropertyWebkitAnimationDelay:
  3761. case CSSPropertyWebkitTransitionDelay:
  3762. currValue = parseAnimationDelay();
  3763. if (currValue)
  3764. m_valueList->next();
  3765. break;
  3766. case CSSPropertyWebkitAnimationDirection:
  3767. currValue = parseAnimationDirection();
  3768. if (currValue)
  3769. m_valueList->next();
  3770. break;
  3771. case CSSPropertyWebkitAnimationDuration:
  3772. case CSSPropertyWebkitTransitionDuration:
  3773. currValue = parseAnimationDuration();
  3774. if (currValue)
  3775. m_valueList->next();
  3776. break;
  3777. case CSSPropertyWebkitAnimationFillMode:
  3778. currValue = parseAnimationFillMode();
  3779. if (currValue)
  3780. m_valueList->next();
  3781. break;
  3782. case CSSPropertyWebkitAnimationIterationCount:
  3783. currValue = parseAnimationIterationCount();
  3784. if (currValue)
  3785. m_valueList->next();
  3786. break;
  3787. case CSSPropertyWebkitAnimationName:
  3788. currValue = parseAnimationName();
  3789. if (currValue)
  3790. m_valueList->next();
  3791. break;
  3792. case CSSPropertyWebkitAnimationPlayState:
  3793. currValue = parseAnimationPlayState();
  3794. if (currValue)
  3795. m_valueList->next();
  3796. break;
  3797. case CSSPropertyWebkitTransitionProperty:
  3798. currValue = parseAnimationProperty();
  3799. if (currValue)
  3800. m_valueList->next();
  3801. break;
  3802. case CSSPropertyWebkitAnimationTimingFunction:
  3803. case CSSPropertyWebkitTransitionTimingFunction:
  3804. currValue = parseAnimationTimingFunction();
  3805. if (currValue)
  3806. m_valueList->next();
  3807. break;
  3808. default:
  3809. ASSERT_NOT_REACHED();
  3810. return false;
  3811. }
  3812. if (!currValue)
  3813. return false;
  3814. if (value && !values) {
  3815. values = CSSValueList::createCommaSeparated();
  3816. values->append(value.release());
  3817. }
  3818. if (values)
  3819. values->append(currValue.release());
  3820. else
  3821. value = currValue.release();
  3822. allowComma = true;
  3823. }
  3824. // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
  3825. // properties.
  3826. if (inShorthand())
  3827. break;
  3828. }
  3829. if (values && values->length()) {
  3830. result = values.release();
  3831. return true;
  3832. }
  3833. if (value) {
  3834. result = value.release();
  3835. return true;
  3836. }
  3837. return false;
  3838. }
  3839. bool CSSParser::parseGridTrackList(CSSPropertyID propId, bool important)
  3840. {
  3841. CSSParserValue* value = m_valueList->current();
  3842. if (value->id == CSSValueNone) {
  3843. if (m_valueList->next())
  3844. return false;
  3845. addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
  3846. return true;
  3847. }
  3848. RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
  3849. while (value) {
  3850. bool valid = validUnit(value, FLength | FPercent) || value->id == CSSValueAuto;
  3851. if (!valid)
  3852. return false;
  3853. RefPtr<CSSPrimitiveValue> primitiveValue = value->id == CSSValueAuto ? cssValuePool().createIdentifierValue(CSSValueAuto) : createPrimitiveNumericValue(value);
  3854. values->append(primitiveValue.release());
  3855. value = m_valueList->next();
  3856. }
  3857. addProperty(propId, values.release(), important);
  3858. return true;
  3859. }
  3860. #if ENABLE(DASHBOARD_SUPPORT)
  3861. #define DASHBOARD_REGION_NUM_PARAMETERS 6
  3862. #define DASHBOARD_REGION_SHORT_NUM_PARAMETERS 2
  3863. static CSSParserValue* skipCommaInDashboardRegion(CSSParserValueList *args)
  3864. {
  3865. if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) ||
  3866. args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
  3867. CSSParserValue* current = args->current();
  3868. if (current->unit == CSSParserValue::Operator && current->iValue == ',')
  3869. return args->next();
  3870. }
  3871. return args->current();
  3872. }
  3873. bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important)
  3874. {
  3875. bool valid = true;
  3876. CSSParserValue* value = m_valueList->current();
  3877. if (value->id == CSSValueNone) {
  3878. if (m_valueList->next())
  3879. return false;
  3880. addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
  3881. return valid;
  3882. }
  3883. RefPtr<DashboardRegion> firstRegion = DashboardRegion::create();
  3884. DashboardRegion* region = 0;
  3885. while (value) {
  3886. if (region == 0) {
  3887. region = firstRegion.get();
  3888. } else {
  3889. RefPtr<DashboardRegion> nextRegion = DashboardRegion::create();
  3890. region->m_next = nextRegion;
  3891. region = nextRegion.get();
  3892. }
  3893. if (value->unit != CSSParserValue::Function) {
  3894. valid = false;
  3895. break;
  3896. }
  3897. // Commas count as values, so allow:
  3898. // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
  3899. // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
  3900. // also allow
  3901. // dashboard-region(label, type) or dashboard-region(label type)
  3902. // dashboard-region(label, type) or dashboard-region(label type)
  3903. CSSParserValueList* args = value->function->args.get();
  3904. if (!equalIgnoringCase(value->function->name, "dashboard-region(") || !args) {
  3905. valid = false;
  3906. break;
  3907. }
  3908. int numArgs = args->size();
  3909. if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) &&
  3910. (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))) {
  3911. valid = false;
  3912. break;
  3913. }
  3914. // First arg is a label.
  3915. CSSParserValue* arg = args->current();
  3916. if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
  3917. valid = false;
  3918. break;
  3919. }
  3920. region->m_label = arg->string;
  3921. // Second arg is a type.
  3922. arg = args->next();
  3923. arg = skipCommaInDashboardRegion(args);
  3924. if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
  3925. valid = false;
  3926. break;
  3927. }
  3928. if (equalIgnoringCase(arg->string, "circle"))
  3929. region->m_isCircle = true;
  3930. else if (equalIgnoringCase(arg->string, "rectangle"))
  3931. region->m_isRectangle = true;
  3932. else {
  3933. valid = false;
  3934. break;
  3935. }
  3936. region->m_geometryType = arg->string;
  3937. if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
  3938. // This originally used CSSValueInvalid by accident. It might be more logical to use something else.
  3939. RefPtr<CSSPrimitiveValue> amount = cssValuePool().createIdentifierValue(CSSValueInvalid);
  3940. region->setTop(amount);
  3941. region->setRight(amount);
  3942. region->setBottom(amount);
  3943. region->setLeft(amount);
  3944. } else {
  3945. // Next four arguments must be offset numbers
  3946. int i;
  3947. for (i = 0; i < 4; i++) {
  3948. arg = args->next();
  3949. arg = skipCommaInDashboardRegion(args);
  3950. valid = arg->id == CSSValueAuto || validUnit(arg, FLength);
  3951. if (!valid)
  3952. break;
  3953. RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ?
  3954. cssValuePool().createIdentifierValue(CSSValueAuto) :
  3955. createPrimitiveNumericValue(arg);
  3956. if (i == 0)
  3957. region->setTop(amount);
  3958. else if (i == 1)
  3959. region->setRight(amount);
  3960. else if (i == 2)
  3961. region->setBottom(amount);
  3962. else
  3963. region->setLeft(amount);
  3964. }
  3965. }
  3966. if (args->next())
  3967. return false;
  3968. value = m_valueList->next();
  3969. }
  3970. if (valid)
  3971. addProperty(propId, cssValuePool().createValue(firstRegion.release()), important);
  3972. return valid;
  3973. }
  3974. #endif /* ENABLE(DASHBOARD_SUPPORT) */
  3975. PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
  3976. {
  3977. unsigned numArgs = args->size();
  3978. if (counters && numArgs != 3 && numArgs != 5)
  3979. return 0;
  3980. if (!counters && numArgs != 1 && numArgs != 3)
  3981. return 0;
  3982. CSSParserValue* i = args->current();
  3983. if (i->unit != CSSPrimitiveValue::CSS_IDENT)
  3984. return 0;
  3985. RefPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i);
  3986. RefPtr<CSSPrimitiveValue> separator;
  3987. if (!counters)
  3988. separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING);
  3989. else {
  3990. i = args->next();
  3991. if (i->unit != CSSParserValue::Operator || i->iValue != ',')
  3992. return 0;
  3993. i = args->next();
  3994. if (i->unit != CSSPrimitiveValue::CSS_STRING)
  3995. return 0;
  3996. separator = createPrimitiveStringValue(i);
  3997. }
  3998. RefPtr<CSSPrimitiveValue> listStyle;
  3999. i = args->next();
  4000. if (!i) // Make the list style default decimal
  4001. listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
  4002. else {
  4003. if (i->unit != CSSParserValue::Operator || i->iValue != ',')
  4004. return 0;
  4005. i = args->next();
  4006. if (i->unit != CSSPrimitiveValue::CSS_IDENT)
  4007. return 0;
  4008. int listStyleID = 0;
  4009. if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha))
  4010. listStyleID = i->id;
  4011. else
  4012. return 0;
  4013. listStyle = cssValuePool().createIdentifierValue(listStyleID);
  4014. }
  4015. return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
  4016. }
  4017. bool CSSParser::parseClipShape(CSSPropertyID propId, bool important)
  4018. {
  4019. CSSParserValue* value = m_valueList->current();
  4020. CSSParserValueList* args = value->function->args.get();
  4021. if (!equalIgnoringCase(value->function->name, "rect(") || !args)
  4022. return false;
  4023. // rect(t, r, b, l) || rect(t r b l)
  4024. if (args->size() != 4 && args->size() != 7)
  4025. return false;
  4026. RefPtr<Rect> rect = Rect::create();
  4027. bool valid = true;
  4028. int i = 0;
  4029. CSSParserValue* a = args->current();
  4030. while (a) {
  4031. valid = a->id == CSSValueAuto || validUnit(a, FLength);
  4032. if (!valid)
  4033. break;
  4034. RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
  4035. cssValuePool().createIdentifierValue(CSSValueAuto) :
  4036. createPrimitiveNumericValue(a);
  4037. if (i == 0)
  4038. rect->setTop(length);
  4039. else if (i == 1)
  4040. rect->setRight(length);
  4041. else if (i == 2)
  4042. rect->setBottom(length);
  4043. else
  4044. rect->setLeft(length);
  4045. a = args->next();
  4046. if (a && args->size() == 7) {
  4047. if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
  4048. a = args->next();
  4049. } else {
  4050. valid = false;
  4051. break;
  4052. }
  4053. }
  4054. i++;
  4055. }
  4056. if (valid) {
  4057. addProperty(propId, cssValuePool().createValue(rect.release()), important);
  4058. m_valueList->next();
  4059. return true;
  4060. }
  4061. return false;
  4062. }
  4063. #if ENABLE(CSS_EXCLUSIONS)
  4064. PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapeRectangle(CSSParserValueList* args)
  4065. {
  4066. ASSERT(args);
  4067. // rect(x, y, width, height, [[rx], ry])
  4068. if (args->size() != 7 && args->size() != 9 && args->size() != 11)
  4069. return 0;
  4070. RefPtr<CSSWrapShapeRectangle> shape = CSSWrapShapeRectangle::create();
  4071. unsigned argumentNumber = 0;
  4072. CSSParserValue* argument = args->current();
  4073. while (argument) {
  4074. if (!validUnit(argument, FLength))
  4075. return 0;
  4076. RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
  4077. ASSERT(argumentNumber < 6);
  4078. switch (argumentNumber) {
  4079. case 0:
  4080. shape->setX(length);
  4081. break;
  4082. case 1:
  4083. shape->setY(length);
  4084. break;
  4085. case 2:
  4086. shape->setWidth(length);
  4087. break;
  4088. case 3:
  4089. shape->setHeight(length);
  4090. break;
  4091. case 4:
  4092. shape->setRadiusX(length);
  4093. break;
  4094. case 5:
  4095. shape->setRadiusY(length);
  4096. break;
  4097. }
  4098. argument = args->next();
  4099. if (argument) {
  4100. if (argument->unit != CSSParserValue::Operator || argument->iValue != ',')
  4101. return 0;
  4102. argument = args->next();
  4103. }
  4104. argumentNumber++;
  4105. }
  4106. if (argumentNumber < 4)
  4107. return 0;
  4108. return shape;
  4109. }
  4110. PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapeCircle(CSSParserValueList* args)
  4111. {
  4112. ASSERT(args);
  4113. // circle(centerX, centerY, radius)
  4114. if (args->size() != 5)
  4115. return 0;
  4116. RefPtr<CSSWrapShapeCircle> shape = CSSWrapShapeCircle::create();
  4117. unsigned argumentNumber = 0;
  4118. CSSParserValue* argument = args->current();
  4119. while (argument) {
  4120. if (!validUnit(argument, FLength))
  4121. return 0;
  4122. RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
  4123. ASSERT(argumentNumber < 3);
  4124. switch (argumentNumber) {
  4125. case 0:
  4126. shape->setCenterX(length);
  4127. break;
  4128. case 1:
  4129. shape->setCenterY(length);
  4130. break;
  4131. case 2:
  4132. shape->setRadius(length);
  4133. break;
  4134. }
  4135. argument = args->next();
  4136. if (argument) {
  4137. if (argument->unit != CSSParserValue::Operator || argument->iValue != ',')
  4138. return 0;
  4139. argument = args->next();
  4140. }
  4141. argumentNumber++;
  4142. }
  4143. if (argumentNumber < 3)
  4144. return 0;
  4145. return shape;
  4146. }
  4147. PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapeEllipse(CSSParserValueList* args)
  4148. {
  4149. ASSERT(args);
  4150. // ellipse(centerX, centerY, radiusX, radiusY)
  4151. if (args->size() != 7)
  4152. return 0;
  4153. RefPtr<CSSWrapShapeEllipse> shape = CSSWrapShapeEllipse::create();
  4154. unsigned argumentNumber = 0;
  4155. CSSParserValue* argument = args->current();
  4156. while (argument) {
  4157. if (!validUnit(argument, FLength))
  4158. return 0;
  4159. RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
  4160. ASSERT(argumentNumber < 4);
  4161. switch (argumentNumber) {
  4162. case 0:
  4163. shape->setCenterX(length);
  4164. break;
  4165. case 1:
  4166. shape->setCenterY(length);
  4167. break;
  4168. case 2:
  4169. shape->setRadiusX(length);
  4170. break;
  4171. case 3:
  4172. shape->setRadiusY(length);
  4173. break;
  4174. }
  4175. argument = args->next();
  4176. if (argument) {
  4177. if (argument->unit != CSSParserValue::Operator || argument->iValue != ',')
  4178. return 0;
  4179. argument = args->next();
  4180. }
  4181. argumentNumber++;
  4182. }
  4183. if (argumentNumber < 4)
  4184. return 0;
  4185. return shape;
  4186. }
  4187. PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapePolygon(CSSParserValueList* args)
  4188. {
  4189. ASSERT(args);
  4190. unsigned size = args->size();
  4191. if (!size)
  4192. return 0;
  4193. RefPtr<CSSWrapShapePolygon> shape = CSSWrapShapePolygon::create();
  4194. CSSParserValue* argument = args->current();
  4195. if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
  4196. shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
  4197. if (!isComma(args->next()))
  4198. return 0;
  4199. argument = args->next();
  4200. size -= 2;
  4201. }
  4202. // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one
  4203. if (!size || (size % 3) - 2)
  4204. return 0;
  4205. CSSParserValue* argumentX = argument;
  4206. while (argumentX) {
  4207. if (!validUnit(argumentX, FLength))
  4208. return 0;
  4209. CSSParserValue* argumentY = args->next();
  4210. if (!argumentY || !validUnit(argumentY, FLength))
  4211. return 0;
  4212. RefPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX);
  4213. RefPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY);
  4214. shape->appendPoint(xLength.release(), yLength.release());
  4215. CSSParserValue* commaOrNull = args->next();
  4216. if (!commaOrNull)
  4217. argumentX = 0;
  4218. else if (!isComma(commaOrNull))
  4219. return 0;
  4220. else
  4221. argumentX = args->next();
  4222. }
  4223. return shape;
  4224. }
  4225. bool CSSParser::parseExclusionShape(bool shapeInside, bool important)
  4226. {
  4227. CSSParserValue* value = m_valueList->current();
  4228. CSSParserValueList* args = value->function->args.get();
  4229. if (!args)
  4230. return false;
  4231. RefPtr<CSSWrapShape> shape;
  4232. if (equalIgnoringCase(value->function->name, "rectangle("))
  4233. shape = parseExclusionShapeRectangle(args);
  4234. else if (equalIgnoringCase(value->function->name, "circle("))
  4235. shape = parseExclusionShapeCircle(args);
  4236. else if (equalIgnoringCase(value->function->name, "ellipse("))
  4237. shape = parseExclusionShapeEllipse(args);
  4238. else if (equalIgnoringCase(value->function->name, "polygon("))
  4239. shape = parseExclusionShapePolygon(args);
  4240. if (shape) {
  4241. addProperty(shapeInside ? CSSPropertyWebkitShapeInside : CSSPropertyWebkitShapeOutside, cssValuePool().createValue(shape.release()), important);
  4242. m_valueList->next();
  4243. return true;
  4244. }
  4245. return false;
  4246. }
  4247. #endif
  4248. // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
  4249. bool CSSParser::parseFont(bool important)
  4250. {
  4251. // Let's check if there is an inherit or initial somewhere in the shorthand.
  4252. for (unsigned i = 0; i < m_valueList->size(); ++i) {
  4253. if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial)
  4254. return false;
  4255. }
  4256. ShorthandScope scope(this, CSSPropertyFont);
  4257. // Optional font-style, font-variant and font-weight.
  4258. bool fontStyleParsed = false;
  4259. bool fontVariantParsed = false;
  4260. bool fontWeightParsed = false;
  4261. CSSParserValue* value;
  4262. while ((value = m_valueList->current())) {
  4263. if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
  4264. addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
  4265. fontStyleParsed = true;
  4266. } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
  4267. // Font variant in the shorthand is particular, it only accepts normal or small-caps.
  4268. addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important);
  4269. fontVariantParsed = true;
  4270. } else if (!fontWeightParsed && parseFontWeight(important))
  4271. fontWeightParsed = true;
  4272. else
  4273. break;
  4274. m_valueList->next();
  4275. }
  4276. if (!value)
  4277. return false;
  4278. if (!fontStyleParsed)
  4279. addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
  4280. if (!fontVariantParsed)
  4281. addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
  4282. if (!fontWeightParsed)
  4283. addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
  4284. // Now a font size _must_ come.
  4285. // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
  4286. if (!parseFontSize(important))
  4287. return false;
  4288. value = m_valueList->current();
  4289. if (!value)
  4290. return false;
  4291. if (value->unit == CSSParserValue::Operator && value->iValue == '/') {
  4292. // The line-height property.
  4293. value = m_valueList->next();
  4294. if (!value)
  4295. return false;
  4296. if (!parseLineHeight(important))
  4297. return false;
  4298. } else
  4299. addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
  4300. // Font family must come now.
  4301. RefPtr<CSSValue> parsedFamilyValue = parseFontFamily();
  4302. if (!parsedFamilyValue)
  4303. return false;
  4304. addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
  4305. // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
  4306. // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
  4307. // but we don't seem to support them at the moment. They should also be added here once implemented.
  4308. if (m_valueList->current())
  4309. return false;
  4310. return true;
  4311. }
  4312. class FontFamilyValueBuilder {
  4313. public:
  4314. FontFamilyValueBuilder(CSSValueList* list)
  4315. : m_list(list)
  4316. {
  4317. }
  4318. void add(const CSSParserString& string)
  4319. {
  4320. if (!m_builder.isEmpty())
  4321. m_builder.append(' ');
  4322. m_builder.append(string.characters, string.length);
  4323. }
  4324. void commit()
  4325. {
  4326. if (m_builder.isEmpty())
  4327. return;
  4328. m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString()));
  4329. m_builder.clear();
  4330. }
  4331. private:
  4332. StringBuilder m_builder;
  4333. CSSValueList* m_list;
  4334. };
  4335. PassRefPtr<CSSValueList> CSSParser::parseFontFamily()
  4336. {
  4337. RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
  4338. CSSParserValue* value = m_valueList->current();
  4339. FontFamilyValueBuilder familyBuilder(list.get());
  4340. bool inFamily = false;
  4341. while (value) {
  4342. if (value->id == CSSValueInitial || value->id == CSSValueInherit)
  4343. return 0;
  4344. CSSParserValue* nextValue = m_valueList->next();
  4345. bool nextValBreaksFont = !nextValue ||
  4346. (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
  4347. bool nextValIsFontName = nextValue &&
  4348. ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
  4349. (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
  4350. if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
  4351. if (inFamily)
  4352. familyBuilder.add(value->string);
  4353. else if (nextValBreaksFont || !nextValIsFontName)
  4354. list->append(cssValuePool().createIdentifierValue(value->id));
  4355. else {
  4356. familyBuilder.commit();
  4357. familyBuilder.add(value->string);
  4358. inFamily = true;
  4359. }
  4360. } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
  4361. // Strings never share in a family name.
  4362. inFamily = false;
  4363. familyBuilder.commit();
  4364. list->append(cssValuePool().createFontFamilyValue(value->string));
  4365. } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
  4366. if (inFamily)
  4367. familyBuilder.add(value->string);
  4368. else if (nextValBreaksFont || !nextValIsFontName)
  4369. list->append(cssValuePool().createFontFamilyValue(value->string));
  4370. else {
  4371. familyBuilder.commit();
  4372. familyBuilder.add(value->string);
  4373. inFamily = true;
  4374. }
  4375. } else {
  4376. break;
  4377. }
  4378. if (!nextValue)
  4379. break;
  4380. if (nextValBreaksFont) {
  4381. value = m_valueList->next();
  4382. familyBuilder.commit();
  4383. inFamily = false;
  4384. }
  4385. else if (nextValIsFontName)
  4386. value = nextValue;
  4387. else
  4388. break;
  4389. }
  4390. familyBuilder.commit();
  4391. if (!list->length())
  4392. list = 0;
  4393. return list.release();
  4394. }
  4395. bool CSSParser::parseLineHeight(bool important)
  4396. {
  4397. CSSParserValue* value = m_valueList->current();
  4398. int id = value->id;
  4399. bool validPrimitive = false;
  4400. // normal | <number> | <length> | <percentage> | inherit
  4401. if (id == CSSValueNormal)
  4402. validPrimitive = true;
  4403. else
  4404. validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
  4405. if (validPrimitive && (!m_valueList->next() || inShorthand()))
  4406. addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important);
  4407. return validPrimitive;
  4408. }
  4409. bool CSSParser::parseFontSize(bool important)
  4410. {
  4411. CSSParserValue* value = m_valueList->current();
  4412. int id = value->id;
  4413. bool validPrimitive = false;
  4414. // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
  4415. if (id >= CSSValueXxSmall && id <= CSSValueLarger)
  4416. validPrimitive = true;
  4417. else
  4418. validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
  4419. if (validPrimitive && (!m_valueList->next() || inShorthand()))
  4420. addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important);
  4421. return validPrimitive;
  4422. }
  4423. bool CSSParser::parseFontVariant(bool important)
  4424. {
  4425. RefPtr<CSSValueList> values;
  4426. if (m_valueList->size() > 1)
  4427. values = CSSValueList::createCommaSeparated();
  4428. CSSParserValue* val;
  4429. bool expectComma = false;
  4430. while ((val = m_valueList->current())) {
  4431. RefPtr<CSSPrimitiveValue> parsedValue;
  4432. if (!expectComma) {
  4433. expectComma = true;
  4434. if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
  4435. parsedValue = cssValuePool().createIdentifierValue(val->id);
  4436. else if (val->id == CSSValueAll && !values) {
  4437. // 'all' is only allowed in @font-face and with no other values. Make a value list to
  4438. // indicate that we are in the @font-face case.
  4439. values = CSSValueList::createCommaSeparated();
  4440. parsedValue = cssValuePool().createIdentifierValue(val->id);
  4441. }
  4442. } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
  4443. expectComma = false;
  4444. m_valueList->next();
  4445. continue;
  4446. }
  4447. if (!parsedValue)
  4448. return false;
  4449. m_valueList->next();
  4450. if (values)
  4451. values->append(parsedValue.release());
  4452. else {
  4453. addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
  4454. return true;
  4455. }
  4456. }
  4457. if (values && values->length()) {
  4458. m_hasFontFaceOnlyValues = true;
  4459. addProperty(CSSPropertyFontVariant, values.release(), important);
  4460. return true;
  4461. }
  4462. return false;
  4463. }
  4464. bool CSSParser::parseFontWeight(bool important)
  4465. {
  4466. CSSParserValue* value = m_valueList->current();
  4467. if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
  4468. addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important);
  4469. return true;
  4470. }
  4471. if (validUnit(value, FInteger | FNonNeg, CSSQuirksMode)) {
  4472. int weight = static_cast<int>(value->fValue);
  4473. if (!(weight % 100) && weight >= 100 && weight <= 900) {
  4474. addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValue100 + weight / 100 - 1), important);
  4475. return true;
  4476. }
  4477. }
  4478. return false;
  4479. }
  4480. bool CSSParser::parseFontFaceSrcURI(CSSValueList* valueList)
  4481. {
  4482. RefPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string)));
  4483. CSSParserValue* value = m_valueList->next();
  4484. if (!value) {
  4485. valueList->append(uriValue.release());
  4486. return true;
  4487. }
  4488. if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
  4489. m_valueList->next();
  4490. valueList->append(uriValue.release());
  4491. return true;
  4492. }
  4493. if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format("))
  4494. return false;
  4495. // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
  4496. // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
  4497. CSSParserValueList* args = value->function->args.get();
  4498. if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
  4499. return false;
  4500. uriValue->setFormat(args->current()->string);
  4501. valueList->append(uriValue.release());
  4502. value = m_valueList->next();
  4503. if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
  4504. m_valueList->next();
  4505. return true;
  4506. }
  4507. bool CSSParser::parseFontFaceSrcLocal(CSSValueList* valueList)
  4508. {
  4509. CSSParserValueList* args = m_valueList->current()->function->args.get();
  4510. if (!args || !args->size())
  4511. return false;
  4512. if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING)
  4513. valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string));
  4514. else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
  4515. StringBuilder builder;
  4516. for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) {
  4517. if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
  4518. return false;
  4519. if (!builder.isEmpty())
  4520. builder.append(' ');
  4521. builder.append(localValue->string);
  4522. }
  4523. valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
  4524. } else
  4525. return false;
  4526. if (CSSParserValue* value = m_valueList->next()) {
  4527. if (value->unit == CSSParserValue::Operator && value->iValue == ',')
  4528. m_valueList->next();
  4529. }
  4530. return true;
  4531. }
  4532. bool CSSParser::parseFontFaceSrc()
  4533. {
  4534. RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
  4535. while (CSSParserValue* value = m_valueList->current()) {
  4536. if (value->unit == CSSPrimitiveValue::CSS_URI) {
  4537. if (!parseFontFaceSrcURI(values.get()))
  4538. return false;
  4539. } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) {
  4540. if (!parseFontFaceSrcLocal(values.get()))
  4541. return false;
  4542. } else
  4543. return false;
  4544. }
  4545. if (!values->length())
  4546. return false;
  4547. addProperty(CSSPropertySrc, values.release(), m_important);
  4548. m_valueList->next();
  4549. return true;
  4550. }
  4551. bool CSSParser::parseFontFaceUnicodeRange()
  4552. {
  4553. RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
  4554. bool failed = false;
  4555. bool operatorExpected = false;
  4556. for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
  4557. if (operatorExpected) {
  4558. if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
  4559. continue;
  4560. failed = true;
  4561. break;
  4562. }
  4563. if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
  4564. failed = true;
  4565. break;
  4566. }
  4567. String rangeString = m_valueList->current()->string;
  4568. UChar32 from = 0;
  4569. UChar32 to = 0;
  4570. unsigned length = rangeString.length();
  4571. if (length < 3) {
  4572. failed = true;
  4573. break;
  4574. }
  4575. unsigned i = 2;
  4576. while (i < length) {
  4577. UChar c = rangeString[i];
  4578. if (c == '-' || c == '?')
  4579. break;
  4580. from *= 16;
  4581. if (c >= '0' && c <= '9')
  4582. from += c - '0';
  4583. else if (c >= 'A' && c <= 'F')
  4584. from += 10 + c - 'A';
  4585. else if (c >= 'a' && c <= 'f')
  4586. from += 10 + c - 'a';
  4587. else {
  4588. failed = true;
  4589. break;
  4590. }
  4591. i++;
  4592. }
  4593. if (failed)
  4594. break;
  4595. if (i == length)
  4596. to = from;
  4597. else if (rangeString[i] == '?') {
  4598. unsigned span = 1;
  4599. while (i < length && rangeString[i] == '?') {
  4600. span *= 16;
  4601. from *= 16;
  4602. i++;
  4603. }
  4604. if (i < length)
  4605. failed = true;
  4606. to = from + span - 1;
  4607. } else {
  4608. if (length < i + 2) {
  4609. failed = true;
  4610. break;
  4611. }
  4612. i++;
  4613. while (i < length) {
  4614. UChar c = rangeString[i];
  4615. to *= 16;
  4616. if (c >= '0' && c <= '9')
  4617. to += c - '0';
  4618. else if (c >= 'A' && c <= 'F')
  4619. to += 10 + c - 'A';
  4620. else if (c >= 'a' && c <= 'f')
  4621. to += 10 + c - 'a';
  4622. else {
  4623. failed = true;
  4624. break;
  4625. }
  4626. i++;
  4627. }
  4628. if (failed)
  4629. break;
  4630. }
  4631. if (from <= to)
  4632. values->append(CSSUnicodeRangeValue::create(from, to));
  4633. }
  4634. if (failed || !values->length())
  4635. return false;
  4636. addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
  4637. return true;
  4638. }
  4639. // Returns the number of characters which form a valid double
  4640. // and are terminated by the given terminator character
  4641. static int checkForValidDouble(const UChar* string, const UChar* end, const char terminator)
  4642. {
  4643. int length = end - string;
  4644. if (length < 1)
  4645. return 0;
  4646. bool decimalMarkSeen = false;
  4647. int processedLength = 0;
  4648. for (int i = 0; i < length; ++i) {
  4649. if (string[i] == terminator) {
  4650. processedLength = i;
  4651. break;
  4652. }
  4653. if (!isASCIIDigit(string[i])) {
  4654. if (!decimalMarkSeen && string[i] == '.')
  4655. decimalMarkSeen = true;
  4656. else
  4657. return 0;
  4658. }
  4659. }
  4660. if (decimalMarkSeen && processedLength == 1)
  4661. return 0;
  4662. return processedLength;
  4663. }
  4664. // Returns the number of characters consumed for parsing a valid double
  4665. // terminated by the given terminator character
  4666. static int parseDouble(const UChar* string, const UChar* end, const char terminator, double& value)
  4667. {
  4668. int length = checkForValidDouble(string, end, terminator);
  4669. if (!length)
  4670. return 0;
  4671. int position = 0;
  4672. double localValue = 0;
  4673. // The consumed characters here are guaranteed to be
  4674. // ASCII digits with or without a decimal mark
  4675. for (; position < length; ++position) {
  4676. if (string[position] == '.')
  4677. break;
  4678. localValue = localValue * 10 + string[position] - '0';
  4679. }
  4680. if (++position == length) {
  4681. value = localValue;
  4682. return length;
  4683. }
  4684. double fraction = 0;
  4685. double scale = 1;
  4686. while (position < length && scale < MAX_SCALE) {
  4687. fraction = fraction * 10 + string[position++] - '0';
  4688. scale *= 10;
  4689. }
  4690. value = localValue + fraction / scale;
  4691. return length;
  4692. }
  4693. static bool parseColorIntOrPercentage(const UChar*& string, const UChar* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
  4694. {
  4695. const UChar* current = string;
  4696. double localValue = 0;
  4697. bool negative = false;
  4698. while (current != end && isHTMLSpace(*current))
  4699. current++;
  4700. if (current != end && *current == '-') {
  4701. negative = true;
  4702. current++;
  4703. }
  4704. if (current == end || !isASCIIDigit(*current))
  4705. return false;
  4706. while (current != end && isASCIIDigit(*current)) {
  4707. double newValue = localValue * 10 + *current++ - '0';
  4708. if (newValue >= 255) {
  4709. // Clamp values at 255.
  4710. localValue = 255;
  4711. while (current != end && isASCIIDigit(*current))
  4712. ++current;
  4713. break;
  4714. }
  4715. localValue = newValue;
  4716. }
  4717. if (current == end)
  4718. return false;
  4719. if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
  4720. return false;
  4721. if (*current == '.') {
  4722. // We already parsed the integral part, try to parse
  4723. // the fraction part of the percentage value.
  4724. double percentage = 0;
  4725. int numCharactersParsed = parseDouble(current, end, '%', percentage);
  4726. if (!numCharactersParsed)
  4727. return false;
  4728. current += numCharactersParsed;
  4729. if (*current != '%')
  4730. return false;
  4731. localValue += percentage;
  4732. }
  4733. if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
  4734. return false;
  4735. if (*current == '%') {
  4736. expect = CSSPrimitiveValue::CSS_PERCENTAGE;
  4737. localValue = localValue / 100.0 * 256.0;
  4738. // Clamp values at 255 for percentages over 100%
  4739. if (localValue > 255)
  4740. localValue = 255;
  4741. current++;
  4742. } else
  4743. expect = CSSPrimitiveValue::CSS_NUMBER;
  4744. while (current != end && isHTMLSpace(*current))
  4745. current++;
  4746. if (current == end || *current++ != terminator)
  4747. return false;
  4748. // Clamp negative values at zero.
  4749. value = negative ? 0 : static_cast<int>(localValue);
  4750. string = current;
  4751. return true;
  4752. }
  4753. static inline bool isTenthAlpha(const UChar* string, const int length)
  4754. {
  4755. // "0.X"
  4756. if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
  4757. return true;
  4758. // ".X"
  4759. if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
  4760. return true;
  4761. return false;
  4762. }
  4763. static inline bool parseAlphaValue(const UChar*& string, const UChar* end, const char terminator, int& value)
  4764. {
  4765. while (string != end && isHTMLSpace(*string))
  4766. string++;
  4767. bool negative = false;
  4768. if (string != end && *string == '-') {
  4769. negative = true;
  4770. string++;
  4771. }
  4772. value = 0;
  4773. int length = end - string;
  4774. if (length < 2)
  4775. return false;
  4776. if (string[length - 1] != terminator)
  4777. return false;
  4778. if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
  4779. if (checkForValidDouble(string, end, terminator)) {
  4780. value = negative ? 0 : 255;
  4781. string = end;
  4782. return true;
  4783. }
  4784. return false;
  4785. }
  4786. if (length == 2 && string[0] != '.') {
  4787. value = !negative && string[0] == '1' ? 255 : 0;
  4788. string = end;
  4789. return true;
  4790. }
  4791. if (isTenthAlpha(string, length - 1)) {
  4792. static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
  4793. value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
  4794. string = end;
  4795. return true;
  4796. }
  4797. double alpha = 0;
  4798. if (!parseDouble(string, end, terminator, alpha))
  4799. return false;
  4800. value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
  4801. string = end;
  4802. return true;
  4803. }
  4804. static inline bool mightBeRGBA(const UChar* characters, unsigned length)
  4805. {
  4806. if (length < 5)
  4807. return false;
  4808. return characters[4] == '('
  4809. && isASCIIAlphaCaselessEqual(characters[0], 'r')
  4810. && isASCIIAlphaCaselessEqual(characters[1], 'g')
  4811. && isASCIIAlphaCaselessEqual(characters[2], 'b')
  4812. && isASCIIAlphaCaselessEqual(characters[3], 'a');
  4813. }
  4814. static inline bool mightBeRGB(const UChar* characters, unsigned length)
  4815. {
  4816. if (length < 4)
  4817. return false;
  4818. return characters[3] == '('
  4819. && isASCIIAlphaCaselessEqual(characters[0], 'r')
  4820. && isASCIIAlphaCaselessEqual(characters[1], 'g')
  4821. && isASCIIAlphaCaselessEqual(characters[2], 'b');
  4822. }
  4823. bool CSSParser::fastParseColor(RGBA32& rgb, const String& name, bool strict)
  4824. {
  4825. const UChar* characters = name.characters();
  4826. unsigned length = name.length();
  4827. CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
  4828. if (!strict && length >= 3) {
  4829. if (name[0] == '#') {
  4830. if (Color::parseHexColor(characters + 1, length - 1, rgb))
  4831. return true;
  4832. } else {
  4833. if (Color::parseHexColor(characters, length, rgb))
  4834. return true;
  4835. }
  4836. }
  4837. // Try rgba() syntax.
  4838. if (mightBeRGBA(characters, length)) {
  4839. const UChar* current = characters + 5;
  4840. const UChar* end = characters + length;
  4841. int red;
  4842. int green;
  4843. int blue;
  4844. int alpha;
  4845. if (!parseColorIntOrPercentage(current, end, ',', expect, red))
  4846. return false;
  4847. if (!parseColorIntOrPercentage(current, end, ',', expect, green))
  4848. return false;
  4849. if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
  4850. return false;
  4851. if (!parseAlphaValue(current, end, ')', alpha))
  4852. return false;
  4853. if (current != end)
  4854. return false;
  4855. rgb = makeRGBA(red, green, blue, alpha);
  4856. return true;
  4857. }
  4858. // Try rgb() syntax.
  4859. if (mightBeRGB(characters, length)) {
  4860. const UChar* current = characters + 4;
  4861. const UChar* end = characters + length;
  4862. int red;
  4863. int green;
  4864. int blue;
  4865. if (!parseColorIntOrPercentage(current, end, ',', expect, red))
  4866. return false;
  4867. if (!parseColorIntOrPercentage(current, end, ',', expect, green))
  4868. return false;
  4869. if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
  4870. return false;
  4871. if (current != end)
  4872. return false;
  4873. rgb = makeRGB(red, green, blue);
  4874. return true;
  4875. }
  4876. // Try named colors.
  4877. Color tc;
  4878. tc.setNamedColor(name);
  4879. if (tc.isValid()) {
  4880. rgb = tc.rgb();
  4881. return true;
  4882. }
  4883. return false;
  4884. }
  4885. inline double CSSParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc)
  4886. {
  4887. const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue;
  4888. if (releaseCalc == ReleaseParsedCalcValue)
  4889. m_parsedCalculation.release();
  4890. return result;
  4891. }
  4892. bool CSSParser::isCalculation(CSSParserValue* value)
  4893. {
  4894. return (value->unit == CSSParserValue::Function)
  4895. && (equalIgnoringCase(value->function->name, "-webkit-calc(")
  4896. || equalIgnoringCase(value->function->name, "-webkit-min(")
  4897. || equalIgnoringCase(value->function->name, "-webkit-max("));
  4898. }
  4899. inline int CSSParser::colorIntFromValue(CSSParserValue* v)
  4900. {
  4901. bool isPercent;
  4902. if (m_parsedCalculation)
  4903. isPercent = m_parsedCalculation->category() == CalcPercent;
  4904. else
  4905. isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
  4906. const double value = parsedDouble(v, ReleaseParsedCalcValue);
  4907. if (value <= 0.0)
  4908. return 0;
  4909. if (isPercent) {
  4910. if (value >= 100.0)
  4911. return 255;
  4912. return static_cast<int>(value * 256.0 / 100.0);
  4913. }
  4914. if (value >= 255.0)
  4915. return 255;
  4916. return static_cast<int>(value);
  4917. }
  4918. bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
  4919. {
  4920. CSSParserValueList* args = value->function->args.get();
  4921. CSSParserValue* v = args->current();
  4922. Units unitType = FUnknown;
  4923. // Get the first value and its type
  4924. if (validUnit(v, FInteger, CSSStrictMode))
  4925. unitType = FInteger;
  4926. else if (validUnit(v, FPercent, CSSStrictMode))
  4927. unitType = FPercent;
  4928. else
  4929. return false;
  4930. colorArray[0] = colorIntFromValue(v);
  4931. for (int i = 1; i < 3; i++) {
  4932. v = args->next();
  4933. if (v->unit != CSSParserValue::Operator && v->iValue != ',')
  4934. return false;
  4935. v = args->next();
  4936. if (!validUnit(v, unitType, CSSStrictMode))
  4937. return false;
  4938. colorArray[i] = colorIntFromValue(v);
  4939. }
  4940. if (parseAlpha) {
  4941. v = args->next();
  4942. if (v->unit != CSSParserValue::Operator && v->iValue != ',')
  4943. return false;
  4944. v = args->next();
  4945. if (!validUnit(v, FNumber, CSSStrictMode))
  4946. return false;
  4947. const double value = parsedDouble(v, ReleaseParsedCalcValue);
  4948. // Convert the floating pointer number of alpha to an integer in the range [0, 256),
  4949. // with an equal distribution across all 256 values.
  4950. colorArray[3] = static_cast<int>(max(0.0, min(1.0, value)) * nextafter(256.0, 0.0));
  4951. }
  4952. return true;
  4953. }
  4954. // The CSS3 specification defines the format of a HSL color as
  4955. // hsl(<number>, <percent>, <percent>)
  4956. // and with alpha, the format is
  4957. // hsla(<number>, <percent>, <percent>, <number>)
  4958. // The first value, HUE, is in an angle with a value between 0 and 360
  4959. bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
  4960. {
  4961. CSSParserValueList* args = value->function->args.get();
  4962. CSSParserValue* v = args->current();
  4963. // Get the first value
  4964. if (!validUnit(v, FNumber, CSSStrictMode))
  4965. return false;
  4966. // normalize the Hue value and change it to be between 0 and 1.0
  4967. colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0;
  4968. for (int i = 1; i < 3; i++) {
  4969. v = args->next();
  4970. if (v->unit != CSSParserValue::Operator && v->iValue != ',')
  4971. return false;
  4972. v = args->next();
  4973. if (!validUnit(v, FPercent, CSSStrictMode))
  4974. return false;
  4975. colorArray[i] = max(0.0, min(100.0, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0
  4976. }
  4977. if (parseAlpha) {
  4978. v = args->next();
  4979. if (v->unit != CSSParserValue::Operator && v->iValue != ',')
  4980. return false;
  4981. v = args->next();
  4982. if (!validUnit(v, FNumber, CSSStrictMode))
  4983. return false;
  4984. colorArray[3] = max(0.0, min(1.0, parsedDouble(v, ReleaseParsedCalcValue)));
  4985. }
  4986. return true;
  4987. }
  4988. PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value)
  4989. {
  4990. RGBA32 c = Color::transparent;
  4991. if (!parseColorFromValue(value ? value : m_valueList->current(), c))
  4992. return 0;
  4993. return cssValuePool().createColorValue(c);
  4994. }
  4995. bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
  4996. {
  4997. if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
  4998. && value->fValue >= 0. && value->fValue < 1000000.) {
  4999. String str = String::format("%06d", static_cast<int>((value->fValue+.5)));
  5000. // FIXME: This should be strict parsing for SVG as well.
  5001. if (!fastParseColor(c, str, inStrictMode()))
  5002. return false;
  5003. } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
  5004. value->unit == CSSPrimitiveValue::CSS_IDENT ||
  5005. (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
  5006. if (!fastParseColor(c, value->string, inStrictMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
  5007. return false;
  5008. } else if (value->unit == CSSParserValue::Function &&
  5009. value->function->args != 0 &&
  5010. value->function->args->size() == 5 /* rgb + two commas */ &&
  5011. equalIgnoringCase(value->function->name, "rgb(")) {
  5012. int colorValues[3];
  5013. if (!parseColorParameters(value, colorValues, false))
  5014. return false;
  5015. c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
  5016. } else {
  5017. if (value->unit == CSSParserValue::Function &&
  5018. value->function->args != 0 &&
  5019. value->function->args->size() == 7 /* rgba + three commas */ &&
  5020. equalIgnoringCase(value->function->name, "rgba(")) {
  5021. int colorValues[4];
  5022. if (!parseColorParameters(value, colorValues, true))
  5023. return false;
  5024. c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
  5025. } else if (value->unit == CSSParserValue::Function &&
  5026. value->function->args != 0 &&
  5027. value->function->args->size() == 5 /* hsl + two commas */ &&
  5028. equalIgnoringCase(value->function->name, "hsl(")) {
  5029. double colorValues[3];
  5030. if (!parseHSLParameters(value, colorValues, false))
  5031. return false;
  5032. c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
  5033. } else if (value->unit == CSSParserValue::Function &&
  5034. value->function->args != 0 &&
  5035. value->function->args->size() == 7 /* hsla + three commas */ &&
  5036. equalIgnoringCase(value->function->name, "hsla(")) {
  5037. double colorValues[4];
  5038. if (!parseHSLParameters(value, colorValues, true))
  5039. return false;
  5040. c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
  5041. } else
  5042. return false;
  5043. }
  5044. return true;
  5045. }
  5046. // This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return)
  5047. // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
  5048. struct ShadowParseContext {
  5049. ShadowParseContext(CSSPropertyID prop, CSSParser* parser)
  5050. : property(prop)
  5051. , m_parser(parser)
  5052. , allowX(true)
  5053. , allowY(false)
  5054. , allowBlur(false)
  5055. , allowSpread(false)
  5056. , allowColor(true)
  5057. , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
  5058. , allowBreak(true)
  5059. {
  5060. }
  5061. bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
  5062. void commitValue()
  5063. {
  5064. // Handle the ,, case gracefully by doing nothing.
  5065. if (x || y || blur || spread || color || style) {
  5066. if (!values)
  5067. values = CSSValueList::createCommaSeparated();
  5068. // Construct the current shadow value and add it to the list.
  5069. values->append(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
  5070. }
  5071. // Now reset for the next shadow value.
  5072. x = 0;
  5073. y = 0;
  5074. blur = 0;
  5075. spread = 0;
  5076. style = 0;
  5077. color = 0;
  5078. allowX = true;
  5079. allowColor = true;
  5080. allowBreak = true;
  5081. allowY = false;
  5082. allowBlur = false;
  5083. allowSpread = false;
  5084. allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
  5085. }
  5086. void commitLength(CSSParserValue* v)
  5087. {
  5088. RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
  5089. if (allowX) {
  5090. x = val.release();
  5091. allowX = false;
  5092. allowY = true;
  5093. allowColor = false;
  5094. allowStyle = false;
  5095. allowBreak = false;
  5096. } else if (allowY) {
  5097. y = val.release();
  5098. allowY = false;
  5099. allowBlur = true;
  5100. allowColor = true;
  5101. allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
  5102. allowBreak = true;
  5103. } else if (allowBlur) {
  5104. blur = val.release();
  5105. allowBlur = false;
  5106. allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
  5107. } else if (allowSpread) {
  5108. spread = val.release();
  5109. allowSpread = false;
  5110. }
  5111. }
  5112. void commitColor(PassRefPtr<CSSPrimitiveValue> val)
  5113. {
  5114. color = val;
  5115. allowColor = false;
  5116. if (allowX) {
  5117. allowStyle = false;
  5118. allowBreak = false;
  5119. } else {
  5120. allowBlur = false;
  5121. allowSpread = false;
  5122. allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
  5123. }
  5124. }
  5125. void commitStyle(CSSParserValue* v)
  5126. {
  5127. style = cssValuePool().createIdentifierValue(v->id);
  5128. allowStyle = false;
  5129. if (allowX)
  5130. allowBreak = false;
  5131. else {
  5132. allowBlur = false;
  5133. allowSpread = false;
  5134. allowColor = false;
  5135. }
  5136. }
  5137. CSSPropertyID property;
  5138. CSSParser* m_parser;
  5139. RefPtr<CSSValueList> values;
  5140. RefPtr<CSSPrimitiveValue> x;
  5141. RefPtr<CSSPrimitiveValue> y;
  5142. RefPtr<CSSPrimitiveValue> blur;
  5143. RefPtr<CSSPrimitiveValue> spread;
  5144. RefPtr<CSSPrimitiveValue> style;
  5145. RefPtr<CSSPrimitiveValue> color;
  5146. bool allowX;
  5147. bool allowY;
  5148. bool allowBlur;
  5149. bool allowSpread;
  5150. bool allowColor;
  5151. bool allowStyle; // inset or not.
  5152. bool allowBreak;
  5153. };
  5154. PassRefPtr<CSSValueList> CSSParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId)
  5155. {
  5156. ShadowParseContext context(propId, this);
  5157. CSSParserValue* val;
  5158. while ((val = valueList->current())) {
  5159. // Check for a comma break first.
  5160. if (val->unit == CSSParserValue::Operator) {
  5161. if (val->iValue != ',' || !context.allowBreak)
  5162. // Other operators aren't legal or we aren't done with the current shadow
  5163. // value. Treat as invalid.
  5164. return 0;
  5165. #if ENABLE(SVG)
  5166. // -webkit-svg-shadow does not support multiple values.
  5167. if (propId == CSSPropertyWebkitSvgShadow)
  5168. return 0;
  5169. #endif
  5170. // The value is good. Commit it.
  5171. context.commitValue();
  5172. } else if (validUnit(val, FLength, CSSStrictMode)) {
  5173. // We required a length and didn't get one. Invalid.
  5174. if (!context.allowLength())
  5175. return 0;
  5176. // A length is allowed here. Construct the value and add it.
  5177. context.commitLength(val);
  5178. } else if (val->id == CSSValueInset) {
  5179. if (!context.allowStyle)
  5180. return 0;
  5181. context.commitStyle(val);
  5182. } else {
  5183. // The only other type of value that's ok is a color value.
  5184. RefPtr<CSSPrimitiveValue> parsedColor;
  5185. bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu
  5186. || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode())
  5187. || val->id == CSSValueCurrentcolor);
  5188. if (isColor) {
  5189. if (!context.allowColor)
  5190. return 0;
  5191. parsedColor = cssValuePool().createIdentifierValue(val->id);
  5192. }
  5193. if (!parsedColor)
  5194. // It's not built-in. Try to parse it as a color.
  5195. parsedColor = parseColor(val);
  5196. if (!parsedColor || !context.allowColor)
  5197. return 0; // This value is not a color or length and is invalid or
  5198. // it is a color, but a color isn't allowed at this point.
  5199. context.commitColor(parsedColor.release());
  5200. }
  5201. valueList->next();
  5202. }
  5203. if (context.allowBreak) {
  5204. context.commitValue();
  5205. if (context.values && context.values->length())
  5206. return context.values.release();
  5207. }
  5208. return 0;
  5209. }
  5210. bool CSSParser::parseReflect(CSSPropertyID propId, bool important)
  5211. {
  5212. // box-reflect: <direction> <offset> <mask>
  5213. // Direction comes first.
  5214. CSSParserValue* val = m_valueList->current();
  5215. CSSReflectionDirection direction;
  5216. switch (val->id) {
  5217. case CSSValueAbove:
  5218. direction = ReflectionAbove;
  5219. break;
  5220. case CSSValueBelow:
  5221. direction = ReflectionBelow;
  5222. break;
  5223. case CSSValueLeft:
  5224. direction = ReflectionLeft;
  5225. break;
  5226. case CSSValueRight:
  5227. direction = ReflectionRight;
  5228. break;
  5229. default:
  5230. return false;
  5231. }
  5232. // The offset comes next.
  5233. val = m_valueList->next();
  5234. RefPtr<CSSPrimitiveValue> offset;
  5235. if (!val)
  5236. offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
  5237. else {
  5238. if (!validUnit(val, FLength | FPercent))
  5239. return false;
  5240. offset = createPrimitiveNumericValue(val);
  5241. }
  5242. // Now for the mask.
  5243. RefPtr<CSSValue> mask;
  5244. val = m_valueList->next();
  5245. if (val) {
  5246. if (!parseBorderImage(propId, mask))
  5247. return false;
  5248. }
  5249. RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction, offset.release(), mask.release());
  5250. addProperty(propId, reflectValue.release(), important);
  5251. m_valueList->next();
  5252. return true;
  5253. }
  5254. #if ENABLE(CSS3_FLEXBOX)
  5255. bool CSSParser::parseFlex(CSSParserValueList* args, bool important)
  5256. {
  5257. if (!args || !args->size() || args->size() > 3)
  5258. return false;
  5259. static const double unsetValue = -1;
  5260. double flexGrow = unsetValue;
  5261. double flexShrink = unsetValue;
  5262. RefPtr<CSSPrimitiveValue> flexBasis;
  5263. while (CSSParserValue* arg = args->current()) {
  5264. if (validUnit(arg, FNumber | FNonNeg)) {
  5265. if (flexGrow == unsetValue)
  5266. flexGrow = arg->fValue;
  5267. else if (flexShrink == unsetValue)
  5268. flexShrink = arg->fValue;
  5269. else if (!arg->fValue) {
  5270. // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
  5271. flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
  5272. } else {
  5273. // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
  5274. return false;
  5275. }
  5276. } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg)))
  5277. flexBasis = parseValidPrimitive(arg->id, arg);
  5278. else {
  5279. // Not a valid arg for flex.
  5280. return false;
  5281. }
  5282. args->next();
  5283. }
  5284. if (flexGrow == unsetValue)
  5285. flexGrow = 0;
  5286. if (flexShrink == unsetValue)
  5287. flexShrink = 1;
  5288. if (!flexBasis)
  5289. flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
  5290. addProperty(CSSPropertyWebkitFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
  5291. addProperty(CSSPropertyWebkitFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
  5292. addProperty(CSSPropertyWebkitFlexBasis, flexBasis, important);
  5293. return true;
  5294. }
  5295. #endif
  5296. struct BorderImageParseContext {
  5297. BorderImageParseContext()
  5298. : m_canAdvance(false)
  5299. , m_allowCommit(true)
  5300. , m_allowImage(true)
  5301. , m_allowImageSlice(true)
  5302. , m_allowRepeat(true)
  5303. , m_allowSlash(false)
  5304. , m_requireWidth(false)
  5305. , m_requireOutset(false)
  5306. {}
  5307. bool canAdvance() const { return m_canAdvance; }
  5308. void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
  5309. bool allowCommit() const { return m_allowCommit; }
  5310. bool allowImage() const { return m_allowImage; }
  5311. bool allowImageSlice() const { return m_allowImageSlice; }
  5312. bool allowRepeat() const { return m_allowRepeat; }
  5313. bool allowSlash() const { return m_allowSlash; }
  5314. bool requireWidth() const { return m_requireWidth; }
  5315. bool requireOutset() const { return m_requireOutset; }
  5316. void commitImage(PassRefPtr<CSSValue> image)
  5317. {
  5318. m_image = image;
  5319. m_canAdvance = true;
  5320. m_allowCommit = true;
  5321. m_allowImage = m_allowSlash = m_requireWidth = m_requireOutset = false;
  5322. m_allowImageSlice = !m_imageSlice;
  5323. m_allowRepeat = !m_repeat;
  5324. }
  5325. void commitImageSlice(PassRefPtr<CSSBorderImageSliceValue> slice)
  5326. {
  5327. m_imageSlice = slice;
  5328. m_canAdvance = true;
  5329. m_allowCommit = m_allowSlash = true;
  5330. m_allowImageSlice = m_requireWidth = m_requireOutset = false;
  5331. m_allowImage = !m_image;
  5332. m_allowRepeat = !m_repeat;
  5333. }
  5334. void commitSlash()
  5335. {
  5336. m_canAdvance = true;
  5337. m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowSlash = false;
  5338. if (!m_borderSlice) {
  5339. m_requireWidth = true;
  5340. m_requireOutset = false;
  5341. } else {
  5342. m_requireOutset = true;
  5343. m_requireWidth = false;
  5344. }
  5345. }
  5346. void commitBorderWidth(PassRefPtr<CSSPrimitiveValue> slice)
  5347. {
  5348. m_borderSlice = slice;
  5349. m_canAdvance = true;
  5350. m_allowCommit = m_allowSlash = true;
  5351. m_allowImageSlice = m_requireWidth = m_requireOutset = false;
  5352. m_allowImage = !m_image;
  5353. m_allowRepeat = !m_repeat;
  5354. }
  5355. void commitBorderOutset(PassRefPtr<CSSPrimitiveValue> outset)
  5356. {
  5357. m_outset = outset;
  5358. m_canAdvance = true;
  5359. m_allowCommit = true;
  5360. m_allowImageSlice = m_allowSlash = m_requireWidth = m_requireOutset = false;
  5361. m_allowImage = !m_image;
  5362. m_allowRepeat = !m_repeat;
  5363. }
  5364. void commitRepeat(PassRefPtr<CSSValue> repeat)
  5365. {
  5366. m_repeat = repeat;
  5367. m_canAdvance = true;
  5368. m_allowCommit = true;
  5369. m_allowRepeat = m_allowSlash = m_requireWidth = m_requireOutset = false;
  5370. m_allowImageSlice = !m_imageSlice;
  5371. m_allowImage = !m_image;
  5372. }
  5373. PassRefPtr<CSSValue> commitWebKitBorderImage()
  5374. {
  5375. return createBorderImageValue(m_image, m_imageSlice, m_borderSlice, m_outset, m_repeat);
  5376. }
  5377. void commitBorderImage(CSSParser* parser, bool important)
  5378. {
  5379. commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
  5380. commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice, important);
  5381. commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice, important);
  5382. commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset, important);
  5383. commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important);
  5384. }
  5385. void commitBorderImageProperty(CSSPropertyID propId, CSSParser* parser, PassRefPtr<CSSValue> value, bool important)
  5386. {
  5387. if (value)
  5388. parser->addProperty(propId, value, important);
  5389. else
  5390. parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true);
  5391. }
  5392. bool m_canAdvance;
  5393. bool m_allowCommit;
  5394. bool m_allowImage;
  5395. bool m_allowImageSlice;
  5396. bool m_allowRepeat;
  5397. bool m_allowSlash;
  5398. bool m_requireWidth;
  5399. bool m_requireOutset;
  5400. RefPtr<CSSValue> m_image;
  5401. RefPtr<CSSBorderImageSliceValue> m_imageSlice;
  5402. RefPtr<CSSPrimitiveValue> m_borderSlice;
  5403. RefPtr<CSSPrimitiveValue> m_outset;
  5404. RefPtr<CSSValue> m_repeat;
  5405. };
  5406. bool CSSParser::parseBorderImage(CSSPropertyID propId, RefPtr<CSSValue>& result, bool important)
  5407. {
  5408. ShorthandScope scope(this, propId);
  5409. BorderImageParseContext context;
  5410. while (CSSParserValue* val = m_valueList->current()) {
  5411. context.setCanAdvance(false);
  5412. if (!context.canAdvance() && context.allowSlash() && val->unit == CSSParserValue::Operator && val->iValue == '/')
  5413. context.commitSlash();
  5414. if (!context.canAdvance() && context.allowImage()) {
  5415. if (val->unit == CSSPrimitiveValue::CSS_URI)
  5416. context.commitImage(CSSImageValue::create(completeURL(val->string)));
  5417. else if (isGeneratedImageValue(val)) {
  5418. RefPtr<CSSValue> value;
  5419. if (parseGeneratedImage(m_valueList.get(), value))
  5420. context.commitImage(value);
  5421. else
  5422. return false;
  5423. #if ENABLE(CSS_IMAGE_SET)
  5424. } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
  5425. RefPtr<CSSValue> value = parseImageSet(m_valueList.get());
  5426. if (value)
  5427. context.commitImage(value);
  5428. else
  5429. return false;
  5430. #endif
  5431. } else if (val->id == CSSValueNone)
  5432. context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone));
  5433. }
  5434. if (!context.canAdvance() && context.allowImageSlice()) {
  5435. RefPtr<CSSBorderImageSliceValue> imageSlice;
  5436. if (parseBorderImageSlice(propId, imageSlice))
  5437. context.commitImageSlice(imageSlice.release());
  5438. }
  5439. if (!context.canAdvance() && context.allowRepeat()) {
  5440. RefPtr<CSSValue> repeat;
  5441. if (parseBorderImageRepeat(repeat))
  5442. context.commitRepeat(repeat);
  5443. }
  5444. if (!context.canAdvance() && context.requireWidth()) {
  5445. RefPtr<CSSPrimitiveValue> borderSlice;
  5446. if (parseBorderImageWidth(borderSlice))
  5447. context.commitBorderWidth(borderSlice.release());
  5448. }
  5449. if (!context.canAdvance() && context.requireOutset()) {
  5450. RefPtr<CSSPrimitiveValue> borderOutset;
  5451. if (parseBorderImageOutset(borderOutset))
  5452. context.commitBorderOutset(borderOutset.release());
  5453. }
  5454. if (!context.canAdvance())
  5455. return false;
  5456. m_valueList->next();
  5457. }
  5458. if (context.allowCommit()) {
  5459. if (propId == CSSPropertyBorderImage)
  5460. context.commitBorderImage(this, important);
  5461. else
  5462. // Need to fully commit as a single value.
  5463. result = context.commitWebKitBorderImage();
  5464. return true;
  5465. }
  5466. return false;
  5467. }
  5468. static bool isBorderImageRepeatKeyword(int id)
  5469. {
  5470. return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
  5471. }
  5472. bool CSSParser::parseBorderImageRepeat(RefPtr<CSSValue>& result)
  5473. {
  5474. RefPtr<CSSPrimitiveValue> firstValue;
  5475. RefPtr<CSSPrimitiveValue> secondValue;
  5476. CSSParserValue* val = m_valueList->current();
  5477. if (isBorderImageRepeatKeyword(val->id))
  5478. firstValue = cssValuePool().createIdentifierValue(val->id);
  5479. else
  5480. return false;
  5481. val = m_valueList->next();
  5482. if (val) {
  5483. if (isBorderImageRepeatKeyword(val->id))
  5484. secondValue = cssValuePool().createIdentifierValue(val->id);
  5485. else if (!inShorthand()) {
  5486. // If we're not parsing a shorthand then we are invalid.
  5487. return false;
  5488. } else {
  5489. // We need to rewind the value list, so that when its advanced we'll
  5490. // end up back at this value.
  5491. m_valueList->previous();
  5492. }
  5493. } else
  5494. secondValue = firstValue;
  5495. result = cssValuePool().createValue(Pair::create(firstValue, secondValue));
  5496. return true;
  5497. }
  5498. class BorderImageSliceParseContext {
  5499. public:
  5500. BorderImageSliceParseContext(CSSParser* parser)
  5501. : m_parser(parser)
  5502. , m_allowNumber(true)
  5503. , m_allowFill(true)
  5504. , m_allowFinalCommit(false)
  5505. , m_fill(false)
  5506. { }
  5507. bool allowNumber() const { return m_allowNumber; }
  5508. bool allowFill() const { return m_allowFill; }
  5509. bool allowFinalCommit() const { return m_allowFinalCommit; }
  5510. CSSPrimitiveValue* top() const { return m_top.get(); }
  5511. void commitNumber(CSSParserValue* v)
  5512. {
  5513. RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
  5514. if (!m_top)
  5515. m_top = val;
  5516. else if (!m_right)
  5517. m_right = val;
  5518. else if (!m_bottom)
  5519. m_bottom = val;
  5520. else {
  5521. ASSERT(!m_left);
  5522. m_left = val;
  5523. }
  5524. m_allowNumber = !m_left;
  5525. m_allowFinalCommit = true;
  5526. }
  5527. void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; }
  5528. PassRefPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
  5529. {
  5530. // We need to clone and repeat values for any omissions.
  5531. ASSERT(m_top);
  5532. if (!m_right) {
  5533. m_right = m_top;
  5534. m_bottom = m_top;
  5535. m_left = m_top;
  5536. }
  5537. if (!m_bottom) {
  5538. m_bottom = m_top;
  5539. m_left = m_right;
  5540. }
  5541. if (!m_left)
  5542. m_left = m_right;
  5543. // Now build a rect value to hold all four of our primitive values.
  5544. RefPtr<Quad> quad = Quad::create();
  5545. quad->setTop(m_top);
  5546. quad->setRight(m_right);
  5547. quad->setBottom(m_bottom);
  5548. quad->setLeft(m_left);
  5549. // Make our new border image value now.
  5550. return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill);
  5551. }
  5552. private:
  5553. CSSParser* m_parser;
  5554. bool m_allowNumber;
  5555. bool m_allowFill;
  5556. bool m_allowFinalCommit;
  5557. RefPtr<CSSPrimitiveValue> m_top;
  5558. RefPtr<CSSPrimitiveValue> m_right;
  5559. RefPtr<CSSPrimitiveValue> m_bottom;
  5560. RefPtr<CSSPrimitiveValue> m_left;
  5561. bool m_fill;
  5562. };
  5563. bool CSSParser::parseBorderImageSlice(CSSPropertyID propId, RefPtr<CSSBorderImageSliceValue>& result)
  5564. {
  5565. BorderImageSliceParseContext context(this);
  5566. CSSParserValue* val;
  5567. while ((val = m_valueList->current())) {
  5568. // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
  5569. if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, CSSStrictMode)) {
  5570. context.commitNumber(val);
  5571. } else if (context.allowFill() && val->id == CSSValueFill)
  5572. context.commitFill();
  5573. else if (!inShorthand()) {
  5574. // If we're not parsing a shorthand then we are invalid.
  5575. return false;
  5576. } else {
  5577. if (context.allowFinalCommit()) {
  5578. // We're going to successfully parse, but we don't want to consume this token.
  5579. m_valueList->previous();
  5580. }
  5581. break;
  5582. }
  5583. m_valueList->next();
  5584. }
  5585. if (context.allowFinalCommit()) {
  5586. // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
  5587. // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
  5588. if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
  5589. context.commitFill();
  5590. // Need to fully commit as a single value.
  5591. result = context.commitBorderImageSlice();
  5592. return true;
  5593. }
  5594. return false;
  5595. }
  5596. class BorderImageQuadParseContext {
  5597. public:
  5598. BorderImageQuadParseContext(CSSParser* parser)
  5599. : m_parser(parser)
  5600. , m_allowNumber(true)
  5601. , m_allowFinalCommit(false)
  5602. { }
  5603. bool allowNumber() const { return m_allowNumber; }
  5604. bool allowFinalCommit() const { return m_allowFinalCommit; }
  5605. CSSPrimitiveValue* top() const { return m_top.get(); }
  5606. void commitNumber(CSSParserValue* v)
  5607. {
  5608. RefPtr<CSSPrimitiveValue> val;
  5609. if (v->id == CSSValueAuto)
  5610. val = cssValuePool().createIdentifierValue(v->id);
  5611. else
  5612. val = m_parser->createPrimitiveNumericValue(v);
  5613. if (!m_top)
  5614. m_top = val;
  5615. else if (!m_right)
  5616. m_right = val;
  5617. else if (!m_bottom)
  5618. m_bottom = val;
  5619. else {
  5620. ASSERT(!m_left);
  5621. m_left = val;
  5622. }
  5623. m_allowNumber = !m_left;
  5624. m_allowFinalCommit = true;
  5625. }
  5626. void setAllowFinalCommit() { m_allowFinalCommit = true; }
  5627. void setTop(PassRefPtr<CSSPrimitiveValue> val) { m_top = val; }
  5628. PassRefPtr<CSSPrimitiveValue> commitBorderImageQuad()
  5629. {
  5630. // We need to clone and repeat values for any omissions.
  5631. ASSERT(m_top);
  5632. if (!m_right) {
  5633. m_right = m_top;
  5634. m_bottom = m_top;
  5635. m_left = m_top;
  5636. }
  5637. if (!m_bottom) {
  5638. m_bottom = m_top;
  5639. m_left = m_right;
  5640. }
  5641. if (!m_left)
  5642. m_left = m_right;
  5643. // Now build a quad value to hold all four of our primitive values.
  5644. RefPtr<Quad> quad = Quad::create();
  5645. quad->setTop(m_top);
  5646. quad->setRight(m_right);
  5647. quad->setBottom(m_bottom);
  5648. quad->setLeft(m_left);
  5649. // Make our new value now.
  5650. return cssValuePool().createValue(quad.release());
  5651. }
  5652. private:
  5653. CSSParser* m_parser;
  5654. bool m_allowNumber;
  5655. bool m_allowFinalCommit;
  5656. RefPtr<CSSPrimitiveValue> m_top;
  5657. RefPtr<CSSPrimitiveValue> m_right;
  5658. RefPtr<CSSPrimitiveValue> m_bottom;
  5659. RefPtr<CSSPrimitiveValue> m_left;
  5660. };
  5661. bool CSSParser::parseBorderImageQuad(Units validUnits, RefPtr<CSSPrimitiveValue>& result)
  5662. {
  5663. BorderImageQuadParseContext context(this);
  5664. CSSParserValue* val;
  5665. while ((val = m_valueList->current())) {
  5666. if (context.allowNumber() && (validUnit(val, validUnits, CSSStrictMode) || val->id == CSSValueAuto)) {
  5667. context.commitNumber(val);
  5668. } else if (!inShorthand()) {
  5669. // If we're not parsing a shorthand then we are invalid.
  5670. return false;
  5671. } else {
  5672. if (context.allowFinalCommit())
  5673. m_valueList->previous(); // The shorthand loop will advance back to this point.
  5674. break;
  5675. }
  5676. m_valueList->next();
  5677. }
  5678. if (context.allowFinalCommit()) {
  5679. // Need to fully commit as a single value.
  5680. result = context.commitBorderImageQuad();
  5681. return true;
  5682. }
  5683. return false;
  5684. }
  5685. bool CSSParser::parseBorderImageWidth(RefPtr<CSSPrimitiveValue>& result)
  5686. {
  5687. return parseBorderImageQuad(FLength | FInteger | FNonNeg | FPercent, result);
  5688. }
  5689. bool CSSParser::parseBorderImageOutset(RefPtr<CSSPrimitiveValue>& result)
  5690. {
  5691. return parseBorderImageQuad(FLength | FInteger | FNonNeg, result);
  5692. }
  5693. static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4])
  5694. {
  5695. if (radii[3])
  5696. return;
  5697. if (!radii[2]) {
  5698. if (!radii[1])
  5699. radii[1] = radii[0];
  5700. radii[2] = radii[0];
  5701. }
  5702. radii[3] = radii[1];
  5703. }
  5704. bool CSSParser::parseBorderRadius(CSSPropertyID propId, bool important)
  5705. {
  5706. unsigned num = m_valueList->size();
  5707. if (num > 9)
  5708. return false;
  5709. ShorthandScope scope(this, propId);
  5710. RefPtr<CSSPrimitiveValue> radii[2][4];
  5711. unsigned indexAfterSlash = 0;
  5712. for (unsigned i = 0; i < num; ++i) {
  5713. CSSParserValue* value = m_valueList->valueAt(i);
  5714. if (value->unit == CSSParserValue::Operator) {
  5715. if (value->iValue != '/')
  5716. return false;
  5717. if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
  5718. return false;
  5719. indexAfterSlash = i + 1;
  5720. completeBorderRadii(radii[0]);
  5721. continue;
  5722. }
  5723. if (i - indexAfterSlash >= 4)
  5724. return false;
  5725. if (!validUnit(value, FLength | FPercent | FNonNeg))
  5726. return false;
  5727. RefPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
  5728. if (!indexAfterSlash) {
  5729. radii[0][i] = radius;
  5730. // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
  5731. if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
  5732. indexAfterSlash = 1;
  5733. completeBorderRadii(radii[0]);
  5734. }
  5735. } else
  5736. radii[1][i - indexAfterSlash] = radius.release();
  5737. }
  5738. if (!indexAfterSlash) {
  5739. completeBorderRadii(radii[0]);
  5740. for (unsigned i = 0; i < 4; ++i)
  5741. radii[1][i] = radii[0][i];
  5742. } else
  5743. completeBorderRadii(radii[1]);
  5744. ImplicitScope implicitScope(this, PropertyImplicit);
  5745. addProperty(CSSPropertyBorderTopLeftRadius, cssValuePool().createValue(Pair::create(radii[0][0].release(), radii[1][0].release())), important);
  5746. addProperty(CSSPropertyBorderTopRightRadius, cssValuePool().createValue(Pair::create(radii[0][1].release(), radii[1][1].release())), important);
  5747. addProperty(CSSPropertyBorderBottomRightRadius, cssValuePool().createValue(Pair::create(radii[0][2].release(), radii[1][2].release())), important);
  5748. addProperty(CSSPropertyBorderBottomLeftRadius, cssValuePool().createValue(Pair::create(radii[0][3].release(), radii[1][3].release())), important);
  5749. return true;
  5750. }
  5751. bool CSSParser::parseAspectRatio(bool important)
  5752. {
  5753. unsigned num = m_valueList->size();
  5754. if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
  5755. addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(CSSValueNone), important);
  5756. return true;
  5757. }
  5758. if (num != 3)
  5759. return false;
  5760. CSSParserValue* lvalue = m_valueList->valueAt(0);
  5761. CSSParserValue* op = m_valueList->valueAt(1);
  5762. CSSParserValue* rvalue = m_valueList->valueAt(2);
  5763. if (op->unit != CSSParserValue::Operator || op->iValue != '/')
  5764. return false;
  5765. if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
  5766. return false;
  5767. if (!lvalue->fValue || !rvalue->fValue)
  5768. return false;
  5769. addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important);
  5770. return true;
  5771. }
  5772. bool CSSParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important)
  5773. {
  5774. enum { ID, VAL } state = ID;
  5775. RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
  5776. RefPtr<CSSPrimitiveValue> counterName;
  5777. while (true) {
  5778. CSSParserValue* val = m_valueList->current();
  5779. switch (state) {
  5780. case ID:
  5781. if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
  5782. counterName = createPrimitiveStringValue(val);
  5783. state = VAL;
  5784. m_valueList->next();
  5785. continue;
  5786. }
  5787. break;
  5788. case VAL: {
  5789. int i = defaultValue;
  5790. if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
  5791. i = clampToInteger(val->fValue);
  5792. m_valueList->next();
  5793. }
  5794. list->append(cssValuePool().createValue(Pair::create(counterName.release(),
  5795. cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER))));
  5796. state = ID;
  5797. continue;
  5798. }
  5799. }
  5800. break;
  5801. }
  5802. if (list->length() > 0) {
  5803. addProperty(propId, list.release(), important);
  5804. return true;
  5805. }
  5806. return false;
  5807. }
  5808. // This should go away once we drop support for -webkit-gradient
  5809. static PassRefPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
  5810. {
  5811. RefPtr<CSSPrimitiveValue> result;
  5812. if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
  5813. if ((equalIgnoringCase(a->string, "left") && horizontal)
  5814. || (equalIgnoringCase(a->string, "top") && !horizontal))
  5815. result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
  5816. else if ((equalIgnoringCase(a->string, "right") && horizontal)
  5817. || (equalIgnoringCase(a->string, "bottom") && !horizontal))
  5818. result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
  5819. else if (equalIgnoringCase(a->string, "center"))
  5820. result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
  5821. } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
  5822. result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(a->unit));
  5823. return result;
  5824. }
  5825. static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
  5826. {
  5827. if (a->unit != CSSParserValue::Function)
  5828. return false;
  5829. if (!equalIgnoringCase(a->function->name, "from(") &&
  5830. !equalIgnoringCase(a->function->name, "to(") &&
  5831. !equalIgnoringCase(a->function->name, "color-stop("))
  5832. return false;
  5833. CSSParserValueList* args = a->function->args.get();
  5834. if (!args)
  5835. return false;
  5836. if (equalIgnoringCase(a->function->name, "from(")
  5837. || equalIgnoringCase(a->function->name, "to(")) {
  5838. // The "from" and "to" stops expect 1 argument.
  5839. if (args->size() != 1)
  5840. return false;
  5841. if (equalIgnoringCase(a->function->name, "from("))
  5842. stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
  5843. else
  5844. stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
  5845. int id = args->current()->id;
  5846. if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
  5847. stop.m_color = cssValuePool().createIdentifierValue(id);
  5848. else
  5849. stop.m_color = p->parseColor(args->current());
  5850. if (!stop.m_color)
  5851. return false;
  5852. }
  5853. // The "color-stop" function expects 3 arguments.
  5854. if (equalIgnoringCase(a->function->name, "color-stop(")) {
  5855. if (args->size() != 3)
  5856. return false;
  5857. CSSParserValue* stopArg = args->current();
  5858. if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
  5859. stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
  5860. else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
  5861. stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
  5862. else
  5863. return false;
  5864. stopArg = args->next();
  5865. if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
  5866. return false;
  5867. stopArg = args->next();
  5868. int id = stopArg->id;
  5869. if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
  5870. stop.m_color = cssValuePool().createIdentifierValue(id);
  5871. else
  5872. stop.m_color = p->parseColor(stopArg);
  5873. if (!stop.m_color)
  5874. return false;
  5875. }
  5876. return true;
  5877. }
  5878. bool CSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient)
  5879. {
  5880. // Walk the arguments.
  5881. CSSParserValueList* args = valueList->current()->function->args.get();
  5882. if (!args || args->size() == 0)
  5883. return false;
  5884. // The first argument is the gradient type. It is an identifier.
  5885. CSSGradientType gradientType;
  5886. CSSParserValue* a = args->current();
  5887. if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
  5888. return false;
  5889. if (equalIgnoringCase(a->string, "linear"))
  5890. gradientType = CSSLinearGradient;
  5891. else if (equalIgnoringCase(a->string, "radial"))
  5892. gradientType = CSSRadialGradient;
  5893. else
  5894. return false;
  5895. RefPtr<CSSGradientValue> result;
  5896. switch (gradientType) {
  5897. case CSSLinearGradient:
  5898. result = CSSLinearGradientValue::create(NonRepeating, true);
  5899. break;
  5900. case CSSRadialGradient:
  5901. result = CSSRadialGradientValue::create(NonRepeating, true);
  5902. break;
  5903. }
  5904. // Comma.
  5905. a = args->next();
  5906. if (!isComma(a))
  5907. return false;
  5908. // Next comes the starting point for the gradient as an x y pair. There is no
  5909. // comma between the x and the y values.
  5910. // First X. It can be left, right, number or percent.
  5911. a = args->next();
  5912. if (!a)
  5913. return false;
  5914. RefPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
  5915. if (!point)
  5916. return false;
  5917. result->setFirstX(point.release());
  5918. // First Y. It can be top, bottom, number or percent.
  5919. a = args->next();
  5920. if (!a)
  5921. return false;
  5922. point = parseDeprecatedGradientPoint(a, false);
  5923. if (!point)
  5924. return false;
  5925. result->setFirstY(point.release());
  5926. // Comma after the first point.
  5927. a = args->next();
  5928. if (!isComma(a))
  5929. return false;
  5930. // For radial gradients only, we now expect a numeric radius.
  5931. if (gradientType == CSSRadialGradient) {
  5932. a = args->next();
  5933. if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
  5934. return false;
  5935. static_cast<CSSRadialGradientValue*>(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
  5936. // Comma after the first radius.
  5937. a = args->next();
  5938. if (!isComma(a))
  5939. return false;
  5940. }
  5941. // Next is the ending point for the gradient as an x, y pair.
  5942. // Second X. It can be left, right, number or percent.
  5943. a = args->next();
  5944. if (!a)
  5945. return false;
  5946. point = parseDeprecatedGradientPoint(a, true);
  5947. if (!point)
  5948. return false;
  5949. result->setSecondX(point.release());
  5950. // Second Y. It can be top, bottom, number or percent.
  5951. a = args->next();
  5952. if (!a)
  5953. return false;
  5954. point = parseDeprecatedGradientPoint(a, false);
  5955. if (!point)
  5956. return false;
  5957. result->setSecondY(point.release());
  5958. // For radial gradients only, we now expect the second radius.
  5959. if (gradientType == CSSRadialGradient) {
  5960. // Comma after the second point.
  5961. a = args->next();
  5962. if (!isComma(a))
  5963. return false;
  5964. a = args->next();
  5965. if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
  5966. return false;
  5967. static_cast<CSSRadialGradientValue*>(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
  5968. }
  5969. // We now will accept any number of stops (0 or more).
  5970. a = args->next();
  5971. while (a) {
  5972. // Look for the comma before the next stop.
  5973. if (!isComma(a))
  5974. return false;
  5975. // Now examine the stop itself.
  5976. a = args->next();
  5977. if (!a)
  5978. return false;
  5979. // The function name needs to be one of "from", "to", or "color-stop."
  5980. CSSGradientColorStop stop;
  5981. if (!parseDeprecatedGradientColorStop(this, a, stop))
  5982. return false;
  5983. result->addStop(stop);
  5984. // Advance
  5985. a = args->next();
  5986. }
  5987. gradient = result.release();
  5988. return true;
  5989. }
  5990. static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
  5991. {
  5992. if (a->unit != CSSPrimitiveValue::CSS_IDENT)
  5993. return 0;
  5994. switch (a->id) {
  5995. case CSSValueLeft:
  5996. case CSSValueRight:
  5997. isHorizontal = true;
  5998. break;
  5999. case CSSValueTop:
  6000. case CSSValueBottom:
  6001. isHorizontal = false;
  6002. break;
  6003. default:
  6004. return 0;
  6005. }
  6006. return cssValuePool().createIdentifierValue(a->id);
  6007. }
  6008. static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSParser* p, CSSParserValue* value)
  6009. {
  6010. int id = value->id;
  6011. if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
  6012. return cssValuePool().createIdentifierValue(id);
  6013. return p->parseColor(value);
  6014. }
  6015. bool CSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
  6016. {
  6017. RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating);
  6018. // Walk the arguments.
  6019. CSSParserValueList* args = valueList->current()->function->args.get();
  6020. if (!args || !args->size())
  6021. return false;
  6022. CSSParserValue* a = args->current();
  6023. if (!a)
  6024. return false;
  6025. bool expectComma = false;
  6026. // Look for angle.
  6027. if (validUnit(a, FAngle, CSSStrictMode)) {
  6028. result->setAngle(createPrimitiveNumericValue(a));
  6029. args->next();
  6030. expectComma = true;
  6031. } else {
  6032. // Look one or two optional keywords that indicate a side or corner.
  6033. RefPtr<CSSPrimitiveValue> startX, startY;
  6034. RefPtr<CSSPrimitiveValue> location;
  6035. bool isHorizontal = false;
  6036. if ((location = valueFromSideKeyword(a, isHorizontal))) {
  6037. if (isHorizontal)
  6038. startX = location;
  6039. else
  6040. startY = location;
  6041. if ((a = args->next())) {
  6042. if ((location = valueFromSideKeyword(a, isHorizontal))) {
  6043. if (isHorizontal) {
  6044. if (startX)
  6045. return false;
  6046. startX = location;
  6047. } else {
  6048. if (startY)
  6049. return false;
  6050. startY = location;
  6051. }
  6052. args->next();
  6053. }
  6054. }
  6055. expectComma = true;
  6056. }
  6057. if (!startX && !startY)
  6058. startY = cssValuePool().createIdentifierValue(CSSValueTop);
  6059. result->setFirstX(startX.release());
  6060. result->setFirstY(startY.release());
  6061. }
  6062. if (!parseGradientColorStops(args, result.get(), expectComma))
  6063. return false;
  6064. Vector<CSSGradientColorStop>& stops = result->stops();
  6065. if (stops.isEmpty())
  6066. return false;
  6067. gradient = result.release();
  6068. return true;
  6069. }
  6070. bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
  6071. {
  6072. RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating);
  6073. // Walk the arguments.
  6074. CSSParserValueList* args = valueList->current()->function->args.get();
  6075. if (!args || !args->size())
  6076. return false;
  6077. CSSParserValue* a = args->current();
  6078. if (!a)
  6079. return false;
  6080. bool expectComma = false;
  6081. // Optional background-position
  6082. RefPtr<CSSValue> centerX;
  6083. RefPtr<CSSValue> centerY;
  6084. // parseFillPosition advances the args next pointer.
  6085. parseFillPosition(args, centerX, centerY);
  6086. a = args->current();
  6087. if (!a)
  6088. return false;
  6089. if (centerX || centerY) {
  6090. // Comma
  6091. if (!isComma(a))
  6092. return false;
  6093. a = args->next();
  6094. if (!a)
  6095. return false;
  6096. }
  6097. ASSERT(!centerX || centerX->isPrimitiveValue());
  6098. ASSERT(!centerY || centerY->isPrimitiveValue());
  6099. result->setFirstX(static_cast<CSSPrimitiveValue*>(centerX.get()));
  6100. result->setSecondX(static_cast<CSSPrimitiveValue*>(centerX.get()));
  6101. // CSS3 radial gradients always share the same start and end point.
  6102. result->setFirstY(static_cast<CSSPrimitiveValue*>(centerY.get()));
  6103. result->setSecondY(static_cast<CSSPrimitiveValue*>(centerY.get()));
  6104. RefPtr<CSSPrimitiveValue> shapeValue;
  6105. RefPtr<CSSPrimitiveValue> sizeValue;
  6106. // Optional shape and/or size in any order.
  6107. for (int i = 0; i < 2; ++i) {
  6108. if (a->unit != CSSPrimitiveValue::CSS_IDENT)
  6109. break;
  6110. bool foundValue = false;
  6111. switch (a->id) {
  6112. case CSSValueCircle:
  6113. case CSSValueEllipse:
  6114. shapeValue = cssValuePool().createIdentifierValue(a->id);
  6115. foundValue = true;
  6116. break;
  6117. case CSSValueClosestSide:
  6118. case CSSValueClosestCorner:
  6119. case CSSValueFarthestSide:
  6120. case CSSValueFarthestCorner:
  6121. case CSSValueContain:
  6122. case CSSValueCover:
  6123. sizeValue = cssValuePool().createIdentifierValue(a->id);
  6124. foundValue = true;
  6125. break;
  6126. }
  6127. if (foundValue) {
  6128. a = args->next();
  6129. if (!a)
  6130. return false;
  6131. expectComma = true;
  6132. }
  6133. }
  6134. result->setShape(shapeValue);
  6135. result->setSizingBehavior(sizeValue);
  6136. // Or, two lengths or percentages
  6137. RefPtr<CSSPrimitiveValue> horizontalSize;
  6138. RefPtr<CSSPrimitiveValue> verticalSize;
  6139. if (!shapeValue && !sizeValue) {
  6140. if (validUnit(a, FLength | FPercent)) {
  6141. horizontalSize = createPrimitiveNumericValue(a);
  6142. a = args->next();
  6143. if (!a)
  6144. return false;
  6145. expectComma = true;
  6146. }
  6147. if (validUnit(a, FLength | FPercent)) {
  6148. verticalSize = createPrimitiveNumericValue(a);
  6149. a = args->next();
  6150. if (!a)
  6151. return false;
  6152. expectComma = true;
  6153. }
  6154. }
  6155. // Must have neither or both.
  6156. if (!horizontalSize != !verticalSize)
  6157. return false;
  6158. result->setEndHorizontalSize(horizontalSize);
  6159. result->setEndVerticalSize(verticalSize);
  6160. if (!parseGradientColorStops(args, result.get(), expectComma))
  6161. return false;
  6162. gradient = result.release();
  6163. return true;
  6164. }
  6165. bool CSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
  6166. {
  6167. CSSParserValue* a = valueList->current();
  6168. // Now look for color stops.
  6169. while (a) {
  6170. // Look for the comma before the next stop.
  6171. if (expectComma) {
  6172. if (!isComma(a))
  6173. return false;
  6174. a = valueList->next();
  6175. if (!a)
  6176. return false;
  6177. }
  6178. // <color-stop> = <color> [ <percentage> | <length> ]?
  6179. CSSGradientColorStop stop;
  6180. stop.m_color = parseGradientColorOrKeyword(this, a);
  6181. if (!stop.m_color)
  6182. return false;
  6183. a = valueList->next();
  6184. if (a) {
  6185. if (validUnit(a, FLength | FPercent)) {
  6186. stop.m_position = createPrimitiveNumericValue(a);
  6187. a = valueList->next();
  6188. }
  6189. }
  6190. gradient->addStop(stop);
  6191. expectComma = true;
  6192. }
  6193. // Must have 2 or more stops to be valid.
  6194. return gradient->stops().size() > 1;
  6195. }
  6196. bool CSSParser::isGeneratedImageValue(CSSParserValue* val) const
  6197. {
  6198. if (val->unit != CSSParserValue::Function)
  6199. return false;
  6200. return equalIgnoringCase(val->function->name, "-webkit-gradient(")
  6201. || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
  6202. || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
  6203. || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
  6204. || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
  6205. || equalIgnoringCase(val->function->name, "-webkit-canvas(")
  6206. || equalIgnoringCase(val->function->name, "-webkit-cross-fade(");
  6207. }
  6208. bool CSSParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
  6209. {
  6210. CSSParserValue* val = valueList->current();
  6211. if (val->unit != CSSParserValue::Function)
  6212. return false;
  6213. if (equalIgnoringCase(val->function->name, "-webkit-gradient("))
  6214. return parseDeprecatedGradient(valueList, value);
  6215. if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient("))
  6216. return parseLinearGradient(valueList, value, NonRepeating);
  6217. if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient("))
  6218. return parseLinearGradient(valueList, value, Repeating);
  6219. if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient("))
  6220. return parseRadialGradient(valueList, value, NonRepeating);
  6221. if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient("))
  6222. return parseRadialGradient(valueList, value, Repeating);
  6223. if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
  6224. return parseCanvas(valueList, value);
  6225. if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
  6226. return parseCrossfade(valueList, value);
  6227. return false;
  6228. }
  6229. bool CSSParser::parseCrossfade(CSSParserValueList* valueList, RefPtr<CSSValue>& crossfade)
  6230. {
  6231. RefPtr<CSSCrossfadeValue> result;
  6232. // Walk the arguments.
  6233. CSSParserValueList* args = valueList->current()->function->args.get();
  6234. if (!args || args->size() != 5)
  6235. return false;
  6236. CSSParserValue* a = args->current();
  6237. RefPtr<CSSValue> fromImageValue;
  6238. RefPtr<CSSValue> toImageValue;
  6239. // The first argument is the "from" image. It is a fill image.
  6240. if (!a || !parseFillImage(args, fromImageValue))
  6241. return false;
  6242. a = args->next();
  6243. // Skip a comma
  6244. if (!isComma(a))
  6245. return false;
  6246. a = args->next();
  6247. // The second argument is the "to" image. It is a fill image.
  6248. if (!a || !parseFillImage(args, toImageValue))
  6249. return false;
  6250. a = args->next();
  6251. // Skip a comma
  6252. if (!isComma(a))
  6253. return false;
  6254. a = args->next();
  6255. // The third argument is the crossfade value. It is a percentage or a fractional number.
  6256. RefPtr<CSSPrimitiveValue> percentage;
  6257. if (!a)
  6258. return false;
  6259. if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
  6260. percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
  6261. else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
  6262. percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
  6263. else
  6264. return false;
  6265. result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
  6266. result->setPercentage(percentage);
  6267. crossfade = result;
  6268. return true;
  6269. }
  6270. bool CSSParser::parseCanvas(CSSParserValueList* valueList, RefPtr<CSSValue>& canvas)
  6271. {
  6272. // Walk the arguments.
  6273. CSSParserValueList* args = valueList->current()->function->args.get();
  6274. if (!args || args->size() != 1)
  6275. return false;
  6276. // The first argument is the canvas name. It is an identifier.
  6277. CSSParserValue* value = args->current();
  6278. if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
  6279. return false;
  6280. canvas = CSSCanvasValue::create(value->string);
  6281. return true;
  6282. }
  6283. #if ENABLE(CSS_IMAGE_RESOLUTION)
  6284. PassRefPtr<CSSValue> CSSParser::parseImageResolution(CSSParserValueList* valueList)
  6285. {
  6286. RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
  6287. bool haveResolution = false;
  6288. bool haveFromImage = false;
  6289. bool haveSnap = false;
  6290. CSSParserValue* value = valueList->current();
  6291. while (value) {
  6292. if (!haveFromImage && value->id == CSSValueFromImage) {
  6293. list->append(cssValuePool().createIdentifierValue(value->id));
  6294. haveFromImage = true;
  6295. } else if (!haveSnap && value->id == CSSValueSnap) {
  6296. list->append(cssValuePool().createIdentifierValue(value->id));
  6297. haveSnap = true;
  6298. } else if (!haveResolution && validUnit(value, FResolution | FNonNeg) && value->fValue > 0) {
  6299. list->append(createPrimitiveNumericValue(value));
  6300. haveResolution = true;
  6301. } else
  6302. return 0;
  6303. value = m_valueList->next();
  6304. }
  6305. if (!list->length())
  6306. return 0;
  6307. if (!haveFromImage && !haveResolution)
  6308. return 0;
  6309. return list;
  6310. }
  6311. #endif
  6312. #if ENABLE(CSS_IMAGE_SET)
  6313. PassRefPtr<CSSValue> CSSParser::parseImageSet(CSSParserValueList* valueList)
  6314. {
  6315. CSSParserValue* function = valueList->current();
  6316. if (function->unit != CSSParserValue::Function)
  6317. return 0;
  6318. CSSParserValueList* functionArgs = valueList->current()->function->args.get();
  6319. if (!functionArgs || !functionArgs->size() || !functionArgs->current())
  6320. return 0;
  6321. RefPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
  6322. CSSParserValue* arg = functionArgs->current();
  6323. while (arg) {
  6324. if (arg->unit != CSSPrimitiveValue::CSS_URI)
  6325. return 0;
  6326. RefPtr<CSSImageValue> image = CSSImageValue::create(completeURL(arg->string));
  6327. imageSet->append(image);
  6328. arg = functionArgs->next();
  6329. if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
  6330. return 0;
  6331. double imageScaleFactor = 0;
  6332. const String& string = arg->string;
  6333. const UChar* current = string.characters();
  6334. const UChar* end = current + string.length();
  6335. parseDouble(current, end, 'x', imageScaleFactor);
  6336. if (imageScaleFactor <= 0)
  6337. return 0;
  6338. imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER));
  6339. // If there are no more arguments, we're done.
  6340. arg = functionArgs->next();
  6341. if (!arg)
  6342. break;
  6343. // If there are more arguments, they should be after a comma.
  6344. if (!isComma(arg))
  6345. return 0;
  6346. // Skip the comma and move on to the next argument.
  6347. arg = functionArgs->next();
  6348. }
  6349. return imageSet;
  6350. }
  6351. #endif
  6352. class TransformOperationInfo {
  6353. public:
  6354. TransformOperationInfo(const CSSParserString& name)
  6355. : m_type(WebKitCSSTransformValue::UnknownTransformOperation)
  6356. , m_argCount(1)
  6357. , m_allowSingleArgument(false)
  6358. , m_unit(CSSParser::FUnknown)
  6359. {
  6360. if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "scalex(") || equalIgnoringCase(name, "scaley(") || equalIgnoringCase(name, "scalez(")) {
  6361. m_unit = CSSParser::FNumber;
  6362. if (equalIgnoringCase(name, "scale("))
  6363. m_type = WebKitCSSTransformValue::ScaleTransformOperation;
  6364. else if (equalIgnoringCase(name, "scalex("))
  6365. m_type = WebKitCSSTransformValue::ScaleXTransformOperation;
  6366. else if (equalIgnoringCase(name, "scaley("))
  6367. m_type = WebKitCSSTransformValue::ScaleYTransformOperation;
  6368. else
  6369. m_type = WebKitCSSTransformValue::ScaleZTransformOperation;
  6370. } else if (equalIgnoringCase(name, "scale3d(")) {
  6371. m_type = WebKitCSSTransformValue::Scale3DTransformOperation;
  6372. m_argCount = 5;
  6373. m_unit = CSSParser::FNumber;
  6374. } else if (equalIgnoringCase(name, "rotate(")) {
  6375. m_type = WebKitCSSTransformValue::RotateTransformOperation;
  6376. m_unit = CSSParser::FAngle;
  6377. } else if (equalIgnoringCase(name, "rotatex(") ||
  6378. equalIgnoringCase(name, "rotatey(") ||
  6379. equalIgnoringCase(name, "rotatez(")) {
  6380. m_unit = CSSParser::FAngle;
  6381. if (equalIgnoringCase(name, "rotatex("))
  6382. m_type = WebKitCSSTransformValue::RotateXTransformOperation;
  6383. else if (equalIgnoringCase(name, "rotatey("))
  6384. m_type = WebKitCSSTransformValue::RotateYTransformOperation;
  6385. else
  6386. m_type = WebKitCSSTransformValue::RotateZTransformOperation;
  6387. } else if (equalIgnoringCase(name, "rotate3d(")) {
  6388. m_type = WebKitCSSTransformValue::Rotate3DTransformOperation;
  6389. m_argCount = 7;
  6390. m_unit = CSSParser::FNumber;
  6391. } else if (equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "skewx(") || equalIgnoringCase(name, "skewy(")) {
  6392. m_unit = CSSParser::FAngle;
  6393. if (equalIgnoringCase(name, "skew("))
  6394. m_type = WebKitCSSTransformValue::SkewTransformOperation;
  6395. else if (equalIgnoringCase(name, "skewx("))
  6396. m_type = WebKitCSSTransformValue::SkewXTransformOperation;
  6397. else
  6398. m_type = WebKitCSSTransformValue::SkewYTransformOperation;
  6399. } else if (equalIgnoringCase(name, "translate(") || equalIgnoringCase(name, "translatex(") || equalIgnoringCase(name, "translatey(") || equalIgnoringCase(name, "translatez(")) {
  6400. m_unit = CSSParser::FLength | CSSParser::FPercent;
  6401. if (equalIgnoringCase(name, "translate("))
  6402. m_type = WebKitCSSTransformValue::TranslateTransformOperation;
  6403. else if (equalIgnoringCase(name, "translatex("))
  6404. m_type = WebKitCSSTransformValue::TranslateXTransformOperation;
  6405. else if (equalIgnoringCase(name, "translatey("))
  6406. m_type = WebKitCSSTransformValue::TranslateYTransformOperation;
  6407. else
  6408. m_type = WebKitCSSTransformValue::TranslateZTransformOperation;
  6409. } else if (equalIgnoringCase(name, "translate3d(")) {
  6410. m_type = WebKitCSSTransformValue::Translate3DTransformOperation;
  6411. m_argCount = 5;
  6412. m_unit = CSSParser::FLength | CSSParser::FPercent;
  6413. } else if (equalIgnoringCase(name, "matrix(")) {
  6414. m_type = WebKitCSSTransformValue::MatrixTransformOperation;
  6415. m_argCount = 11;
  6416. m_unit = CSSParser::FNumber;
  6417. } else if (equalIgnoringCase(name, "matrix3d(")) {
  6418. m_type = WebKitCSSTransformValue::Matrix3DTransformOperation;
  6419. m_argCount = 31;
  6420. m_unit = CSSParser::FNumber;
  6421. } else if (equalIgnoringCase(name, "perspective(")) {
  6422. m_type = WebKitCSSTransformValue::PerspectiveTransformOperation;
  6423. m_unit = CSSParser::FNumber;
  6424. }
  6425. if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "translate(")) {
  6426. m_allowSingleArgument = true;
  6427. m_argCount = 3;
  6428. }
  6429. }
  6430. WebKitCSSTransformValue::TransformOperationType type() const { return m_type; }
  6431. unsigned argCount() const { return m_argCount; }
  6432. CSSParser::Units unit() const { return m_unit; }
  6433. bool unknown() const { return m_type == WebKitCSSTransformValue::UnknownTransformOperation; }
  6434. bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
  6435. private:
  6436. WebKitCSSTransformValue::TransformOperationType m_type;
  6437. unsigned m_argCount;
  6438. bool m_allowSingleArgument;
  6439. CSSParser::Units m_unit;
  6440. };
  6441. PassRefPtr<CSSValueList> CSSParser::parseTransform()
  6442. {
  6443. if (!m_valueList)
  6444. return 0;
  6445. // The transform is a list of functional primitives that specify transform operations.
  6446. // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation.
  6447. RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
  6448. for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
  6449. if (value->unit != CSSParserValue::Function || !value->function)
  6450. return 0;
  6451. // Every primitive requires at least one argument.
  6452. CSSParserValueList* args = value->function->args.get();
  6453. if (!args)
  6454. return 0;
  6455. // See if the specified primitive is one we understand.
  6456. TransformOperationInfo info(value->function->name);
  6457. if (info.unknown())
  6458. return 0;
  6459. if (!info.hasCorrectArgCount(args->size()))
  6460. return 0;
  6461. // Create the new WebKitCSSTransformValue for this operation and add it to our list.
  6462. RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(info.type());
  6463. list->append(transformValue);
  6464. // Snag our values.
  6465. CSSParserValue* a = args->current();
  6466. unsigned argNumber = 0;
  6467. while (a) {
  6468. CSSParser::Units unit = info.unit();
  6469. if (info.type() == WebKitCSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
  6470. // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
  6471. if (!validUnit(a, FAngle, CSSStrictMode))
  6472. return 0;
  6473. } else if (info.type() == WebKitCSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
  6474. // 3rd param of translate3d() cannot be a percentage
  6475. if (!validUnit(a, FLength, CSSStrictMode))
  6476. return 0;
  6477. } else if (info.type() == WebKitCSSTransformValue::TranslateZTransformOperation && argNumber == 0) {
  6478. // 1st param of translateZ() cannot be a percentage
  6479. if (!validUnit(a, FLength, CSSStrictMode))
  6480. return 0;
  6481. } else if (info.type() == WebKitCSSTransformValue::PerspectiveTransformOperation && argNumber == 0) {
  6482. // 1st param of perspective() must be a non-negative number (deprecated) or length.
  6483. if (!validUnit(a, FNumber | FLength | FNonNeg, CSSStrictMode))
  6484. return 0;
  6485. } else if (!validUnit(a, unit, CSSStrictMode))
  6486. return 0;
  6487. // Add the value to the current transform operation.
  6488. transformValue->append(createPrimitiveNumericValue(a));
  6489. a = args->next();
  6490. if (!a)
  6491. break;
  6492. if (a->unit != CSSParserValue::Operator || a->iValue != ',')
  6493. return 0;
  6494. a = args->next();
  6495. argNumber++;
  6496. }
  6497. }
  6498. return list.release();
  6499. }
  6500. #if ENABLE(CSS_FILTERS)
  6501. static void filterInfoForName(const CSSParserString& name, WebKitCSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
  6502. {
  6503. if (equalIgnoringCase(name, "grayscale("))
  6504. filterType = WebKitCSSFilterValue::GrayscaleFilterOperation;
  6505. else if (equalIgnoringCase(name, "sepia("))
  6506. filterType = WebKitCSSFilterValue::SepiaFilterOperation;
  6507. else if (equalIgnoringCase(name, "saturate("))
  6508. filterType = WebKitCSSFilterValue::SaturateFilterOperation;
  6509. else if (equalIgnoringCase(name, "hue-rotate("))
  6510. filterType = WebKitCSSFilterValue::HueRotateFilterOperation;
  6511. else if (equalIgnoringCase(name, "invert("))
  6512. filterType = WebKitCSSFilterValue::InvertFilterOperation;
  6513. else if (equalIgnoringCase(name, "opacity("))
  6514. filterType = WebKitCSSFilterValue::OpacityFilterOperation;
  6515. else if (equalIgnoringCase(name, "brightness("))
  6516. filterType = WebKitCSSFilterValue::BrightnessFilterOperation;
  6517. else if (equalIgnoringCase(name, "contrast("))
  6518. filterType = WebKitCSSFilterValue::ContrastFilterOperation;
  6519. else if (equalIgnoringCase(name, "blur("))
  6520. filterType = WebKitCSSFilterValue::BlurFilterOperation;
  6521. else if (equalIgnoringCase(name, "drop-shadow(")) {
  6522. filterType = WebKitCSSFilterValue::DropShadowFilterOperation;
  6523. maximumArgumentCount = 4; // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
  6524. }
  6525. #if ENABLE(CSS_SHADERS)
  6526. else if (equalIgnoringCase(name, "custom("))
  6527. filterType = WebKitCSSFilterValue::CustomFilterOperation;
  6528. #endif
  6529. }
  6530. #if ENABLE(CSS_SHADERS)
  6531. static bool acceptCommaOperator(CSSParserValueList* argsList)
  6532. {
  6533. if (CSSParserValue* arg = argsList->current()) {
  6534. if (!isComma(arg))
  6535. return false;
  6536. argsList->next();
  6537. }
  6538. return true;
  6539. }
  6540. PassRefPtr<WebKitCSSFilterValue> CSSParser::parseCustomFilter(CSSParserValue* value)
  6541. {
  6542. CSSParserValueList* argsList = value->function->args.get();
  6543. if (!argsList)
  6544. return 0;
  6545. RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::CustomFilterOperation);
  6546. // Custom filter syntax:
  6547. //
  6548. // vertexShader: <uri> | none
  6549. // fragmentShader: <uri> | none
  6550. //
  6551. // box: filter-box | border-box | padding-box | content-box
  6552. // vertexMesh: +<integer>{1,2}[wsp<box>][wsp'detached']
  6553. //
  6554. // param-value: true|false[wsp+true|false]{0-3} |
  6555. // <number>[wsp+<number>]{0-3} |
  6556. // <array> |
  6557. // <transform> |
  6558. // <texture(<uri>)>
  6559. // array: 'array('<number>[wsp<number>]*')'
  6560. // css-3d-transform: <transform-function>;[<transform-function>]*
  6561. // transform: <css-3d-transform> | <mat>
  6562. // mat: 'mat2('<number>(,<number>){3}')' |
  6563. // 'mat3('<number>(,<number>){8}')' |
  6564. // 'mat4('<number>(,<number>){15}')' )
  6565. // param-def: <param-name>wsp<param-value>
  6566. // param-name: <ident>
  6567. // params: [<param-def>[,<param-def>*]]
  6568. //
  6569. // custom(<vertex-shader>[wsp<fragment-shader>][,<vertex-mesh>][,<params>])
  6570. // 1. Parse the shader URLs: <vertex-shader>[wsp<fragment-shader>]
  6571. RefPtr<CSSValueList> shadersList = CSSValueList::createSpaceSeparated();
  6572. bool hadAtLeastOneCustomShader = false;
  6573. CSSParserValue* arg;
  6574. while ((arg = argsList->current())) {
  6575. RefPtr<CSSValue> value;
  6576. if (arg->id == CSSValueNone)
  6577. value = cssValuePool().createIdentifierValue(CSSValueNone);
  6578. else if (arg->unit == CSSPrimitiveValue::CSS_URI) {
  6579. KURL shaderURL = completeURL(arg->string);
  6580. value = WebKitCSSShaderValue::create(shaderURL.string());
  6581. hadAtLeastOneCustomShader = true;
  6582. }
  6583. if (!value)
  6584. break;
  6585. shadersList->append(value.release());
  6586. argsList->next();
  6587. }
  6588. if (!shadersList->length() || !hadAtLeastOneCustomShader || shadersList->length() > 2 || !acceptCommaOperator(argsList))
  6589. return 0;
  6590. filterValue->append(shadersList.release());
  6591. // 2. Parse the mesh size <vertex-mesh>
  6592. RefPtr<CSSValueList> meshSizeList = CSSValueList::createSpaceSeparated();
  6593. while ((arg = argsList->current())) {
  6594. if (!validUnit(arg, FInteger | FNonNeg, CSSStrictMode))
  6595. break;
  6596. int integerValue = clampToInteger(arg->fValue);
  6597. // According to the specification we can only accept positive non-zero values.
  6598. if (integerValue < 1)
  6599. return 0;
  6600. meshSizeList->append(cssValuePool().createValue(integerValue, CSSPrimitiveValue::CSS_NUMBER));
  6601. argsList->next();
  6602. }
  6603. if (meshSizeList->length() > 2)
  6604. return 0;
  6605. if ((arg = argsList->current()) && (arg->id == CSSValueBorderBox || arg->id == CSSValuePaddingBox
  6606. || arg->id == CSSValueContentBox || arg->id == CSSValueFilterBox)) {
  6607. meshSizeList->append(cssValuePool().createIdentifierValue(arg->id));
  6608. argsList->next();
  6609. }
  6610. if ((arg = argsList->current()) && arg->id == CSSValueDetached) {
  6611. meshSizeList->append(cssValuePool().createIdentifierValue(arg->id));
  6612. argsList->next();
  6613. }
  6614. if (meshSizeList->length()) {
  6615. if (!acceptCommaOperator(argsList))
  6616. return 0;
  6617. filterValue->append(meshSizeList.release());
  6618. }
  6619. // 3. Parser the parameters.
  6620. RefPtr<CSSValueList> paramList = CSSValueList::createCommaSeparated();
  6621. while ((arg = argsList->current())) {
  6622. if (arg->id || arg->unit != CSSPrimitiveValue::CSS_IDENT)
  6623. return 0;
  6624. RefPtr<CSSValueList> parameter = CSSValueList::createSpaceSeparated();
  6625. parameter->append(createPrimitiveStringValue(arg));
  6626. argsList->next();
  6627. if (!(arg = argsList->current()))
  6628. return 0;
  6629. // TODO: Implement other parameters types parsing.
  6630. // textures: https://bugs.webkit.org/show_bug.cgi?id=71442
  6631. // 3d-transforms: https://bugs.webkit.org/show_bug.cgi?id=71443
  6632. // mat2, mat3, mat4: https://bugs.webkit.org/show_bug.cgi?id=71444
  6633. RefPtr<CSSValueList> paramValueList = CSSValueList::createSpaceSeparated();
  6634. while ((arg = argsList->current())) {
  6635. // If we hit a comma it means we finished this parameter's values.
  6636. if (isComma(arg))
  6637. break;
  6638. if (!validUnit(arg, FNumber, CSSStrictMode))
  6639. return 0;
  6640. paramValueList->append(cssValuePool().createValue(arg->fValue, CSSPrimitiveValue::CSS_NUMBER));
  6641. argsList->next();
  6642. }
  6643. if (!paramValueList->length() || paramValueList->length() > 4)
  6644. return 0;
  6645. parameter->append(paramValueList.release());
  6646. paramList->append(parameter.release());
  6647. if (!acceptCommaOperator(argsList))
  6648. return 0;
  6649. }
  6650. if (paramList->length())
  6651. filterValue->append(paramList.release());
  6652. return filterValue;
  6653. }
  6654. #endif
  6655. PassRefPtr<WebKitCSSFilterValue> CSSParser::parseBuiltinFilterArguments(CSSParserValueList* args, WebKitCSSFilterValue::FilterOperationType filterType)
  6656. {
  6657. RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(filterType);
  6658. ASSERT(args);
  6659. switch (filterType) {
  6660. case WebKitCSSFilterValue::GrayscaleFilterOperation:
  6661. case WebKitCSSFilterValue::SepiaFilterOperation:
  6662. case WebKitCSSFilterValue::SaturateFilterOperation:
  6663. case WebKitCSSFilterValue::InvertFilterOperation:
  6664. case WebKitCSSFilterValue::OpacityFilterOperation:
  6665. case WebKitCSSFilterValue::ContrastFilterOperation: {
  6666. // One optional argument, 0-1 or 0%-100%, if missing use 100%.
  6667. if (args->size() > 1)
  6668. return 0;
  6669. if (args->size()) {
  6670. CSSParserValue* value = args->current();
  6671. if (!validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode))
  6672. return 0;
  6673. double amount = value->fValue;
  6674. // Saturate and Contrast allow values over 100%.
  6675. if (filterType != WebKitCSSFilterValue::SaturateFilterOperation
  6676. && filterType != WebKitCSSFilterValue::ContrastFilterOperation) {
  6677. double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
  6678. if (amount > maxAllowed)
  6679. return 0;
  6680. }
  6681. filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
  6682. }
  6683. break;
  6684. }
  6685. case WebKitCSSFilterValue::BrightnessFilterOperation: {
  6686. // One optional argument, -1 to +1 or -100% to +100%, if missing use 0,
  6687. if (args->size() > 1)
  6688. return 0;
  6689. if (args->size()) {
  6690. CSSParserValue* value = args->current();
  6691. if (!validUnit(value, FNumber | FPercent, CSSStrictMode))
  6692. return 0;
  6693. double amount = value->fValue;
  6694. double minAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? -100.0 : -1.0;
  6695. double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
  6696. if (amount < minAllowed || amount > maxAllowed)
  6697. return 0;
  6698. filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
  6699. }
  6700. break;
  6701. }
  6702. case WebKitCSSFilterValue::HueRotateFilterOperation: {
  6703. // hue-rotate() takes one optional angle.
  6704. if (args->size() > 1)
  6705. return 0;
  6706. if (args->size()) {
  6707. CSSParserValue* argument = args->current();
  6708. if (!validUnit(argument, FAngle, CSSStrictMode))
  6709. return 0;
  6710. filterValue->append(createPrimitiveNumericValue(argument));
  6711. }
  6712. break;
  6713. }
  6714. case WebKitCSSFilterValue::BlurFilterOperation: {
  6715. // Blur takes a single length. Zero parameters are allowed.
  6716. if (args->size() > 1)
  6717. return 0;
  6718. if (args->size()) {
  6719. CSSParserValue* argument = args->current();
  6720. if (!validUnit(argument, FLength | FNonNeg, CSSStrictMode))
  6721. return 0;
  6722. filterValue->append(createPrimitiveNumericValue(argument));
  6723. }
  6724. break;
  6725. }
  6726. case WebKitCSSFilterValue::DropShadowFilterOperation: {
  6727. // drop-shadow() takes a single shadow.
  6728. RefPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter);
  6729. if (!shadowValueList || shadowValueList->length() != 1)
  6730. return 0;
  6731. filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0));
  6732. break;
  6733. }
  6734. default:
  6735. ASSERT_NOT_REACHED();
  6736. }
  6737. return filterValue.release();
  6738. }
  6739. PassRefPtr<CSSValueList> CSSParser::parseFilter()
  6740. {
  6741. if (!m_valueList)
  6742. return 0;
  6743. // The filter is a list of functional primitives that specify individual operations.
  6744. RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
  6745. for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
  6746. if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function))
  6747. return 0;
  6748. WebKitCSSFilterValue::FilterOperationType filterType = WebKitCSSFilterValue::UnknownFilterOperation;
  6749. // See if the specified primitive is one we understand.
  6750. if (value->unit == CSSPrimitiveValue::CSS_URI) {
  6751. #if ENABLE(SVG)
  6752. RefPtr<WebKitCSSFilterValue> referenceFilterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::ReferenceFilterOperation);
  6753. list->append(referenceFilterValue);
  6754. referenceFilterValue->append(WebKitCSSSVGDocumentValue::create(value->string));
  6755. #endif
  6756. } else {
  6757. const CSSParserString name = value->function->name;
  6758. unsigned maximumArgumentCount = 1;
  6759. filterInfoForName(name, filterType, maximumArgumentCount);
  6760. if (filterType == WebKitCSSFilterValue::UnknownFilterOperation)
  6761. return 0;
  6762. #if ENABLE(CSS_SHADERS)
  6763. if (filterType == WebKitCSSFilterValue::CustomFilterOperation) {
  6764. // Make sure parsing fails if custom filters are disabled.
  6765. if (!m_context.isCSSCustomFilterEnabled)
  6766. return 0;
  6767. RefPtr<WebKitCSSFilterValue> filterValue = parseCustomFilter(value);
  6768. if (!filterValue)
  6769. return 0;
  6770. list->append(filterValue.release());
  6771. continue;
  6772. }
  6773. #endif
  6774. CSSParserValueList* args = value->function->args.get();
  6775. if (!args)
  6776. return 0;
  6777. RefPtr<WebKitCSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType);
  6778. if (!filterValue)
  6779. return 0;
  6780. list->append(filterValue);
  6781. }
  6782. }
  6783. return list.release();
  6784. }
  6785. #endif
  6786. #if ENABLE(CSS_REGIONS)
  6787. static bool validFlowName(const String& flowName)
  6788. {
  6789. return !(equalIgnoringCase(flowName, "auto")
  6790. || equalIgnoringCase(flowName, "default")
  6791. || equalIgnoringCase(flowName, "inherit")
  6792. || equalIgnoringCase(flowName, "initial")
  6793. || equalIgnoringCase(flowName, "none"));
  6794. }
  6795. #endif
  6796. bool CSSParser::cssRegionsEnabled() const
  6797. {
  6798. return m_context.isCSSRegionsEnabled;
  6799. }
  6800. bool CSSParser::cssGridLayoutEnabled() const
  6801. {
  6802. return m_context.isCSSGridLayoutEnabled;
  6803. }
  6804. #if ENABLE(CSS_REGIONS)
  6805. bool CSSParser::parseFlowThread(const String& flowName)
  6806. {
  6807. setupParser("@-webkit-decls{-webkit-flow-into:", flowName, "}");
  6808. cssyyparse(this);
  6809. m_rule = 0;
  6810. return ((m_parsedProperties.size() == 1) && (m_parsedProperties.first().id() == CSSPropertyWebkitFlowInto));
  6811. }
  6812. // none | <ident>
  6813. bool CSSParser::parseFlowThread(CSSPropertyID propId, bool important)
  6814. {
  6815. ASSERT(propId == CSSPropertyWebkitFlowInto);
  6816. ASSERT(cssRegionsEnabled());
  6817. if (m_valueList->size() != 1)
  6818. return false;
  6819. CSSParserValue* value = m_valueList->current();
  6820. if (!value)
  6821. return false;
  6822. if (value->unit != CSSPrimitiveValue::CSS_IDENT)
  6823. return false;
  6824. if (value->id == CSSValueNone) {
  6825. addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
  6826. return true;
  6827. }
  6828. String inputProperty = String(value->string);
  6829. if (!inputProperty.isEmpty()) {
  6830. if (!validFlowName(inputProperty))
  6831. return false;
  6832. addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
  6833. } else
  6834. addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
  6835. return true;
  6836. }
  6837. // -webkit-flow-from: none | <ident>
  6838. bool CSSParser::parseRegionThread(CSSPropertyID propId, bool important)
  6839. {
  6840. ASSERT(propId == CSSPropertyWebkitFlowFrom);
  6841. ASSERT(cssRegionsEnabled());
  6842. if (m_valueList->size() != 1)
  6843. return false;
  6844. CSSParserValue* value = m_valueList->current();
  6845. if (!value)
  6846. return false;
  6847. if (value->unit != CSSPrimitiveValue::CSS_IDENT)
  6848. return false;
  6849. if (value->id == CSSValueNone)
  6850. addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
  6851. else {
  6852. String inputProperty = String(value->string);
  6853. if (!inputProperty.isEmpty()) {
  6854. if (!validFlowName(inputProperty))
  6855. return false;
  6856. addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
  6857. } else
  6858. addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
  6859. }
  6860. return true;
  6861. }
  6862. #endif
  6863. bool CSSParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
  6864. {
  6865. propId1 = propId;
  6866. propId2 = propId;
  6867. propId3 = propId;
  6868. if (propId == CSSPropertyWebkitTransformOrigin) {
  6869. propId1 = CSSPropertyWebkitTransformOriginX;
  6870. propId2 = CSSPropertyWebkitTransformOriginY;
  6871. propId3 = CSSPropertyWebkitTransformOriginZ;
  6872. }
  6873. switch (propId) {
  6874. case CSSPropertyWebkitTransformOrigin:
  6875. if (!parseTransformOriginShorthand(value, value2, value3))
  6876. return false;
  6877. // parseTransformOriginShorthand advances the m_valueList pointer
  6878. break;
  6879. case CSSPropertyWebkitTransformOriginX: {
  6880. value = parseFillPositionX(m_valueList.get());
  6881. if (value)
  6882. m_valueList->next();
  6883. break;
  6884. }
  6885. case CSSPropertyWebkitTransformOriginY: {
  6886. value = parseFillPositionY(m_valueList.get());
  6887. if (value)
  6888. m_valueList->next();
  6889. break;
  6890. }
  6891. case CSSPropertyWebkitTransformOriginZ: {
  6892. if (validUnit(m_valueList->current(), FLength))
  6893. value = createPrimitiveNumericValue(m_valueList->current());
  6894. if (value)
  6895. m_valueList->next();
  6896. break;
  6897. }
  6898. default:
  6899. ASSERT_NOT_REACHED();
  6900. return false;
  6901. }
  6902. return value;
  6903. }
  6904. bool CSSParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2)
  6905. {
  6906. propId1 = propId;
  6907. propId2 = propId;
  6908. if (propId == CSSPropertyWebkitPerspectiveOrigin) {
  6909. propId1 = CSSPropertyWebkitPerspectiveOriginX;
  6910. propId2 = CSSPropertyWebkitPerspectiveOriginY;
  6911. }
  6912. switch (propId) {
  6913. case CSSPropertyWebkitPerspectiveOrigin:
  6914. parseFillPosition(m_valueList.get(), value, value2);
  6915. break;
  6916. case CSSPropertyWebkitPerspectiveOriginX: {
  6917. value = parseFillPositionX(m_valueList.get());
  6918. if (value)
  6919. m_valueList->next();
  6920. break;
  6921. }
  6922. case CSSPropertyWebkitPerspectiveOriginY: {
  6923. value = parseFillPositionY(m_valueList.get());
  6924. if (value)
  6925. m_valueList->next();
  6926. break;
  6927. }
  6928. default:
  6929. ASSERT_NOT_REACHED();
  6930. return false;
  6931. }
  6932. return value;
  6933. }
  6934. bool CSSParser::parseTextEmphasisStyle(bool important)
  6935. {
  6936. unsigned valueListSize = m_valueList->size();
  6937. RefPtr<CSSPrimitiveValue> fill;
  6938. RefPtr<CSSPrimitiveValue> shape;
  6939. for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
  6940. if (value->unit == CSSPrimitiveValue::CSS_STRING) {
  6941. if (fill || shape || (valueListSize != 1 && !inShorthand()))
  6942. return false;
  6943. addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important);
  6944. m_valueList->next();
  6945. return true;
  6946. }
  6947. if (value->id == CSSValueNone) {
  6948. if (fill || shape || (valueListSize != 1 && !inShorthand()))
  6949. return false;
  6950. addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important);
  6951. m_valueList->next();
  6952. return true;
  6953. }
  6954. if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
  6955. if (fill)
  6956. return false;
  6957. fill = cssValuePool().createIdentifierValue(value->id);
  6958. } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
  6959. if (shape)
  6960. return false;
  6961. shape = cssValuePool().createIdentifierValue(value->id);
  6962. } else if (!inShorthand())
  6963. return false;
  6964. else
  6965. break;
  6966. }
  6967. if (fill && shape) {
  6968. RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
  6969. parsedValues->append(fill.release());
  6970. parsedValues->append(shape.release());
  6971. addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
  6972. return true;
  6973. }
  6974. if (fill) {
  6975. addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
  6976. return true;
  6977. }
  6978. if (shape) {
  6979. addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
  6980. return true;
  6981. }
  6982. return false;
  6983. }
  6984. bool CSSParser::parseLineBoxContain(bool important)
  6985. {
  6986. LineBoxContain lineBoxContain = LineBoxContainNone;
  6987. for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
  6988. if (value->id == CSSValueBlock) {
  6989. if (lineBoxContain & LineBoxContainBlock)
  6990. return false;
  6991. lineBoxContain |= LineBoxContainBlock;
  6992. } else if (value->id == CSSValueInline) {
  6993. if (lineBoxContain & LineBoxContainInline)
  6994. return false;
  6995. lineBoxContain |= LineBoxContainInline;
  6996. } else if (value->id == CSSValueFont) {
  6997. if (lineBoxContain & LineBoxContainFont)
  6998. return false;
  6999. lineBoxContain |= LineBoxContainFont;
  7000. } else if (value->id == CSSValueGlyphs) {
  7001. if (lineBoxContain & LineBoxContainGlyphs)
  7002. return false;
  7003. lineBoxContain |= LineBoxContainGlyphs;
  7004. } else if (value->id == CSSValueReplaced) {
  7005. if (lineBoxContain & LineBoxContainReplaced)
  7006. return false;
  7007. lineBoxContain |= LineBoxContainReplaced;
  7008. } else if (value->id == CSSValueInlineBox) {
  7009. if (lineBoxContain & LineBoxContainInlineBox)
  7010. return false;
  7011. lineBoxContain |= LineBoxContainInlineBox;
  7012. } else
  7013. return false;
  7014. }
  7015. if (!lineBoxContain)
  7016. return false;
  7017. addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
  7018. return true;
  7019. }
  7020. bool CSSParser::parseFontFeatureTag(CSSValueList* settings)
  7021. {
  7022. // Feature tag name consists of 4-letter characters.
  7023. static const int tagNameLength = 4;
  7024. CSSParserValue* value = m_valueList->current();
  7025. // Feature tag name comes first
  7026. if (value->unit != CSSPrimitiveValue::CSS_STRING)
  7027. return false;
  7028. if (value->string.length != tagNameLength)
  7029. return false;
  7030. for (int i = 0; i < tagNameLength; ++i) {
  7031. // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
  7032. UChar character = value->string.characters[i];
  7033. if (character < 0x20 || character > 0x7E)
  7034. return false;
  7035. }
  7036. String tag = value->string;
  7037. int tagValue = 1;
  7038. // Feature tag values could follow: <integer> | on | off
  7039. value = m_valueList->next();
  7040. if (value) {
  7041. if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
  7042. tagValue = clampToInteger(value->fValue);
  7043. if (tagValue < 0)
  7044. return false;
  7045. m_valueList->next();
  7046. } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
  7047. tagValue = value->id == CSSValueOn;
  7048. m_valueList->next();
  7049. }
  7050. }
  7051. settings->append(FontFeatureValue::create(tag, tagValue));
  7052. return true;
  7053. }
  7054. bool CSSParser::parseFontFeatureSettings(bool important)
  7055. {
  7056. if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) {
  7057. RefPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal);
  7058. m_valueList->next();
  7059. addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
  7060. return true;
  7061. }
  7062. RefPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
  7063. for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
  7064. if (!parseFontFeatureTag(settings.get()))
  7065. return false;
  7066. // If the list isn't parsed fully, the current value should be comma.
  7067. value = m_valueList->current();
  7068. if (value && !isComma(value))
  7069. return false;
  7070. }
  7071. if (settings->length()) {
  7072. addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important);
  7073. return true;
  7074. }
  7075. return false;
  7076. }
  7077. bool CSSParser::parseFontVariantLigatures(bool important)
  7078. {
  7079. RefPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
  7080. bool sawCommonLigaturesValue = false;
  7081. bool sawDiscretionaryLigaturesValue = false;
  7082. bool sawHistoricalLigaturesValue = false;
  7083. for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
  7084. if (value->unit != CSSPrimitiveValue::CSS_IDENT)
  7085. return false;
  7086. switch (value->id) {
  7087. case CSSValueNoCommonLigatures:
  7088. case CSSValueCommonLigatures:
  7089. if (sawCommonLigaturesValue)
  7090. return false;
  7091. sawCommonLigaturesValue = true;
  7092. ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
  7093. break;
  7094. case CSSValueNoDiscretionaryLigatures:
  7095. case CSSValueDiscretionaryLigatures:
  7096. if (sawDiscretionaryLigaturesValue)
  7097. return false;
  7098. sawDiscretionaryLigaturesValue = true;
  7099. ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
  7100. break;
  7101. case CSSValueNoHistoricalLigatures:
  7102. case CSSValueHistoricalLigatures:
  7103. if (sawHistoricalLigaturesValue)
  7104. return false;
  7105. sawHistoricalLigaturesValue = true;
  7106. ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
  7107. break;
  7108. default:
  7109. return false;
  7110. }
  7111. }
  7112. if (!ligatureValues->length())
  7113. return false;
  7114. addProperty(CSSPropertyWebkitFontVariantLigatures, ligatureValues.release(), important);
  7115. return true;
  7116. }
  7117. bool CSSParser::parseCalculation(CSSParserValue* value, CalculationPermittedValueRange range)
  7118. {
  7119. ASSERT(isCalculation(value));
  7120. CSSParserValueList* args = value->function->args.get();
  7121. if (!args || !args->size())
  7122. return false;
  7123. ASSERT(!m_parsedCalculation);
  7124. m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
  7125. if (!m_parsedCalculation)
  7126. return false;
  7127. return true;
  7128. }
  7129. #define END_TOKEN 0
  7130. #include "CSSGrammar.h"
  7131. enum CharacterType {
  7132. // Types for the main switch.
  7133. // The first 4 types must be grouped together, as they
  7134. // represent the allowed chars in an identifier.
  7135. CharacterCaselessU,
  7136. CharacterIdentifierStart,
  7137. CharacterNumber,
  7138. CharacterDash,
  7139. CharacterOther,
  7140. CharacterNull,
  7141. CharacterWhiteSpace,
  7142. CharacterEndMediaQuery,
  7143. CharacterEndNthChild,
  7144. CharacterQuote,
  7145. CharacterExclamationMark,
  7146. CharacterHashmark,
  7147. CharacterDollar,
  7148. CharacterAsterisk,
  7149. CharacterPlus,
  7150. CharacterDot,
  7151. CharacterSlash,
  7152. CharacterLess,
  7153. CharacterAt,
  7154. CharacterBackSlash,
  7155. CharacterXor,
  7156. CharacterVerticalBar,
  7157. CharacterTilde,
  7158. };
  7159. // 128 ASCII codes
  7160. static const CharacterType typesOfASCIICharacters[128] = {
  7161. /* 0 - Null */ CharacterNull,
  7162. /* 1 - Start of Heading */ CharacterOther,
  7163. /* 2 - Start of Text */ CharacterOther,
  7164. /* 3 - End of Text */ CharacterOther,
  7165. /* 4 - End of Transm. */ CharacterOther,
  7166. /* 5 - Enquiry */ CharacterOther,
  7167. /* 6 - Acknowledgment */ CharacterOther,
  7168. /* 7 - Bell */ CharacterOther,
  7169. /* 8 - Back Space */ CharacterOther,
  7170. /* 9 - Horizontal Tab */ CharacterWhiteSpace,
  7171. /* 10 - Line Feed */ CharacterWhiteSpace,
  7172. /* 11 - Vertical Tab */ CharacterOther,
  7173. /* 12 - Form Feed */ CharacterWhiteSpace,
  7174. /* 13 - Carriage Return */ CharacterWhiteSpace,
  7175. /* 14 - Shift Out */ CharacterOther,
  7176. /* 15 - Shift In */ CharacterOther,
  7177. /* 16 - Data Line Escape */ CharacterOther,
  7178. /* 17 - Device Control 1 */ CharacterOther,
  7179. /* 18 - Device Control 2 */ CharacterOther,
  7180. /* 19 - Device Control 3 */ CharacterOther,
  7181. /* 20 - Device Control 4 */ CharacterOther,
  7182. /* 21 - Negative Ack. */ CharacterOther,
  7183. /* 22 - Synchronous Idle */ CharacterOther,
  7184. /* 23 - End of Transmit */ CharacterOther,
  7185. /* 24 - Cancel */ CharacterOther,
  7186. /* 25 - End of Medium */ CharacterOther,
  7187. /* 26 - Substitute */ CharacterOther,
  7188. /* 27 - Escape */ CharacterOther,
  7189. /* 28 - File Separator */ CharacterOther,
  7190. /* 29 - Group Separator */ CharacterOther,
  7191. /* 30 - Record Separator */ CharacterOther,
  7192. /* 31 - Unit Separator */ CharacterOther,
  7193. /* 32 - Space */ CharacterWhiteSpace,
  7194. /* 33 - ! */ CharacterExclamationMark,
  7195. /* 34 - " */ CharacterQuote,
  7196. /* 35 - # */ CharacterHashmark,
  7197. /* 36 - $ */ CharacterDollar,
  7198. /* 37 - % */ CharacterOther,
  7199. /* 38 - & */ CharacterOther,
  7200. /* 39 - ' */ CharacterQuote,
  7201. /* 40 - ( */ CharacterOther,
  7202. /* 41 - ) */ CharacterEndNthChild,
  7203. /* 42 - * */ CharacterAsterisk,
  7204. /* 43 - + */ CharacterPlus,
  7205. /* 44 - , */ CharacterOther,
  7206. /* 45 - - */ CharacterDash,
  7207. /* 46 - . */ CharacterDot,
  7208. /* 47 - / */ CharacterSlash,
  7209. /* 48 - 0 */ CharacterNumber,
  7210. /* 49 - 1 */ CharacterNumber,
  7211. /* 50 - 2 */ CharacterNumber,
  7212. /* 51 - 3 */ CharacterNumber,
  7213. /* 52 - 4 */ CharacterNumber,
  7214. /* 53 - 5 */ CharacterNumber,
  7215. /* 54 - 6 */ CharacterNumber,
  7216. /* 55 - 7 */ CharacterNumber,
  7217. /* 56 - 8 */ CharacterNumber,
  7218. /* 57 - 9 */ CharacterNumber,
  7219. /* 58 - : */ CharacterOther,
  7220. /* 59 - ; */ CharacterEndMediaQuery,
  7221. /* 60 - < */ CharacterLess,
  7222. /* 61 - = */ CharacterOther,
  7223. /* 62 - > */ CharacterOther,
  7224. /* 63 - ? */ CharacterOther,
  7225. /* 64 - @ */ CharacterAt,
  7226. /* 65 - A */ CharacterIdentifierStart,
  7227. /* 66 - B */ CharacterIdentifierStart,
  7228. /* 67 - C */ CharacterIdentifierStart,
  7229. /* 68 - D */ CharacterIdentifierStart,
  7230. /* 69 - E */ CharacterIdentifierStart,
  7231. /* 70 - F */ CharacterIdentifierStart,
  7232. /* 71 - G */ CharacterIdentifierStart,
  7233. /* 72 - H */ CharacterIdentifierStart,
  7234. /* 73 - I */ CharacterIdentifierStart,
  7235. /* 74 - J */ CharacterIdentifierStart,
  7236. /* 75 - K */ CharacterIdentifierStart,
  7237. /* 76 - L */ CharacterIdentifierStart,
  7238. /* 77 - M */ CharacterIdentifierStart,
  7239. /* 78 - N */ CharacterIdentifierStart,
  7240. /* 79 - O */ CharacterIdentifierStart,
  7241. /* 80 - P */ CharacterIdentifierStart,
  7242. /* 81 - Q */ CharacterIdentifierStart,
  7243. /* 82 - R */ CharacterIdentifierStart,
  7244. /* 83 - S */ CharacterIdentifierStart,
  7245. /* 84 - T */ CharacterIdentifierStart,
  7246. /* 85 - U */ CharacterCaselessU,
  7247. /* 86 - V */ CharacterIdentifierStart,
  7248. /* 87 - W */ CharacterIdentifierStart,
  7249. /* 88 - X */ CharacterIdentifierStart,
  7250. /* 89 - Y */ CharacterIdentifierStart,
  7251. /* 90 - Z */ CharacterIdentifierStart,
  7252. /* 91 - [ */ CharacterOther,
  7253. /* 92 - \ */ CharacterBackSlash,
  7254. /* 93 - ] */ CharacterOther,
  7255. /* 94 - ^ */ CharacterXor,
  7256. /* 95 - _ */ CharacterIdentifierStart,
  7257. /* 96 - ` */ CharacterOther,
  7258. /* 97 - a */ CharacterIdentifierStart,
  7259. /* 98 - b */ CharacterIdentifierStart,
  7260. /* 99 - c */ CharacterIdentifierStart,
  7261. /* 100 - d */ CharacterIdentifierStart,
  7262. /* 101 - e */ CharacterIdentifierStart,
  7263. /* 102 - f */ CharacterIdentifierStart,
  7264. /* 103 - g */ CharacterIdentifierStart,
  7265. /* 104 - h */ CharacterIdentifierStart,
  7266. /* 105 - i */ CharacterIdentifierStart,
  7267. /* 106 - j */ CharacterIdentifierStart,
  7268. /* 107 - k */ CharacterIdentifierStart,
  7269. /* 108 - l */ CharacterIdentifierStart,
  7270. /* 109 - m */ CharacterIdentifierStart,
  7271. /* 110 - n */ CharacterIdentifierStart,
  7272. /* 111 - o */ CharacterIdentifierStart,
  7273. /* 112 - p */ CharacterIdentifierStart,
  7274. /* 113 - q */ CharacterIdentifierStart,
  7275. /* 114 - r */ CharacterIdentifierStart,
  7276. /* 115 - s */ CharacterIdentifierStart,
  7277. /* 116 - t */ CharacterIdentifierStart,
  7278. /* 117 - u */ CharacterCaselessU,
  7279. /* 118 - v */ CharacterIdentifierStart,
  7280. /* 119 - w */ CharacterIdentifierStart,
  7281. /* 120 - x */ CharacterIdentifierStart,
  7282. /* 121 - y */ CharacterIdentifierStart,
  7283. /* 122 - z */ CharacterIdentifierStart,
  7284. /* 123 - { */ CharacterEndMediaQuery,
  7285. /* 124 - | */ CharacterVerticalBar,
  7286. /* 125 - } */ CharacterOther,
  7287. /* 126 - ~ */ CharacterTilde,
  7288. /* 127 - Delete */ CharacterOther,
  7289. };
  7290. // Utility functions for the CSS tokenizer.
  7291. static inline bool isCSSLetter(UChar character)
  7292. {
  7293. return character >= 128 || typesOfASCIICharacters[character] <= CharacterDash;
  7294. }
  7295. static inline bool isCSSEscape(UChar character)
  7296. {
  7297. return character >= ' ' && character != 127;
  7298. }
  7299. static inline bool isURILetter(UChar character)
  7300. {
  7301. return (character >= '*' && character != 127) || (character >= '#' && character <= '&') || character == '!';
  7302. }
  7303. static inline bool isIdentifierStartAfterDash(UChar* currentCharacter)
  7304. {
  7305. return isASCIIAlpha(currentCharacter[0]) || currentCharacter[0] == '_' || currentCharacter[0] >= 128
  7306. || (currentCharacter[0] == '\\' && isCSSEscape(currentCharacter[1]));
  7307. }
  7308. static inline bool isEqualToCSSIdentifier(UChar* cssString, const char* constantString)
  7309. {
  7310. // Compare an UChar memory data with a zero terminated string.
  7311. do {
  7312. // The input must be part of an identifier if constantChar or constString
  7313. // contains '-'. Otherwise toASCIILowerUnchecked('\r') would be equal to '-'.
  7314. ASSERT((*constantString >= 'a' && *constantString <= 'z') || *constantString == '-');
  7315. ASSERT(*constantString != '-' || isCSSLetter(*cssString));
  7316. if (toASCIILowerUnchecked(*cssString++) != (*constantString++))
  7317. return false;
  7318. } while (*constantString);
  7319. return true;
  7320. }
  7321. static UChar* checkAndSkipEscape(UChar* currentCharacter)
  7322. {
  7323. // Returns with 0, if escape check is failed. Otherwise
  7324. // it returns with the following character.
  7325. ASSERT(*currentCharacter == '\\');
  7326. ++currentCharacter;
  7327. if (!isCSSEscape(*currentCharacter))
  7328. return 0;
  7329. if (isASCIIHexDigit(*currentCharacter)) {
  7330. int length = 6;
  7331. do {
  7332. ++currentCharacter;
  7333. } while (isASCIIHexDigit(*currentCharacter) && --length);
  7334. // Optional space after the escape sequence.
  7335. if (isHTMLSpace(*currentCharacter))
  7336. ++currentCharacter;
  7337. return currentCharacter;
  7338. }
  7339. return currentCharacter + 1;
  7340. }
  7341. static inline UChar* skipWhiteSpace(UChar* currentCharacter)
  7342. {
  7343. while (isHTMLSpace(*currentCharacter))
  7344. ++currentCharacter;
  7345. return currentCharacter;
  7346. }
  7347. // Main CSS tokenizer functions.
  7348. inline bool CSSParser::isIdentifierStart()
  7349. {
  7350. // Check whether an identifier is started.
  7351. return isIdentifierStartAfterDash((*m_currentCharacter != '-') ? m_currentCharacter : m_currentCharacter + 1);
  7352. }
  7353. inline UChar* CSSParser::checkAndSkipString(UChar* currentCharacter, UChar quote)
  7354. {
  7355. // Returns with 0, if string check is failed. Otherwise
  7356. // it returns with the following character. This is necessary
  7357. // since we cannot revert escape sequences, thus strings
  7358. // must be validated before parsing.
  7359. while (true) {
  7360. if (UNLIKELY(*currentCharacter == quote)) {
  7361. // String parsing is successful.
  7362. return currentCharacter + 1;
  7363. }
  7364. if (UNLIKELY(!*currentCharacter)) {
  7365. // String parsing is successful up to end of input.
  7366. return currentCharacter;
  7367. }
  7368. if (UNLIKELY(*currentCharacter <= '\r' && (*currentCharacter == '\n' || (*currentCharacter | 0x1) == '\r'))) {
  7369. // String parsing is failed for character '\n', '\f' or '\r'.
  7370. return 0;
  7371. }
  7372. if (LIKELY(currentCharacter[0] != '\\'))
  7373. ++currentCharacter;
  7374. else if (currentCharacter[1] == '\n' || currentCharacter[1] == '\f')
  7375. currentCharacter += 2;
  7376. else if (currentCharacter[1] == '\r')
  7377. currentCharacter += currentCharacter[2] == '\n' ? 3 : 2;
  7378. else {
  7379. currentCharacter = checkAndSkipEscape(currentCharacter);
  7380. if (!currentCharacter)
  7381. return 0;
  7382. }
  7383. }
  7384. }
  7385. void CSSParser::parseEscape(UChar*& result)
  7386. {
  7387. ASSERT(*m_currentCharacter == '\\' && isCSSEscape(m_currentCharacter[1]));
  7388. ++m_currentCharacter;
  7389. if (isASCIIHexDigit(*m_currentCharacter)) {
  7390. unsigned unicode = 0;
  7391. int length = 6;
  7392. do {
  7393. unicode = (unicode << 4) + toASCIIHexValue(*m_currentCharacter++);
  7394. } while (--length && isASCIIHexDigit(*m_currentCharacter));
  7395. // Characters above 0x10ffff are not handled.
  7396. if (unicode > 0x10ffff)
  7397. unicode = 0xfffd;
  7398. // Optional space after the escape sequence.
  7399. if (isHTMLSpace(*m_currentCharacter))
  7400. ++m_currentCharacter;
  7401. // Replace unicode with a surrogate pairs when it is bigger than 0xffff
  7402. if (U16_LENGTH(unicode) == 2) {
  7403. *result++ = U16_LEAD(unicode);
  7404. *result = U16_TRAIL(unicode);
  7405. } else
  7406. *result = unicode;
  7407. } else
  7408. *result = *m_currentCharacter++;
  7409. ++result;
  7410. }
  7411. inline void CSSParser::parseIdentifier(UChar*& result, bool& hasEscape)
  7412. {
  7413. // If a valid identifier start is found, we can safely
  7414. // parse the identifier until the next invalid character.
  7415. ASSERT(isIdentifierStart());
  7416. hasEscape = false;
  7417. do {
  7418. if (LIKELY(*m_currentCharacter != '\\'))
  7419. *result++ = *m_currentCharacter++;
  7420. else {
  7421. hasEscape = true;
  7422. parseEscape(result);
  7423. }
  7424. } while (isCSSLetter(m_currentCharacter[0]) || (m_currentCharacter[0] == '\\' && isCSSEscape(m_currentCharacter[1])));
  7425. }
  7426. inline void CSSParser::parseString(UChar*& result, UChar quote)
  7427. {
  7428. while (true) {
  7429. if (UNLIKELY(*m_currentCharacter == quote)) {
  7430. // String parsing is done.
  7431. ++m_currentCharacter;
  7432. return;
  7433. }
  7434. if (UNLIKELY(!*m_currentCharacter)) {
  7435. // String parsing is done, but don't advance pointer if at the end of input.
  7436. return;
  7437. }
  7438. ASSERT(*m_currentCharacter > '\r' || (*m_currentCharacter < '\n' && *m_currentCharacter) || *m_currentCharacter == '\v');
  7439. if (LIKELY(m_currentCharacter[0] != '\\'))
  7440. *result++ = *m_currentCharacter++;
  7441. else if (m_currentCharacter[1] == '\n' || m_currentCharacter[1] == '\f')
  7442. m_currentCharacter += 2;
  7443. else if (m_currentCharacter[1] == '\r')
  7444. m_currentCharacter += m_currentCharacter[2] == '\n' ? 3 : 2;
  7445. else
  7446. parseEscape(result);
  7447. }
  7448. }
  7449. inline void CSSParser::parseURI(UChar*& start, UChar*& result)
  7450. {
  7451. UChar* uriStart = skipWhiteSpace(m_currentCharacter);
  7452. if (*uriStart == '"' || *uriStart == '\'') {
  7453. UChar quote = *uriStart;
  7454. ++uriStart;
  7455. UChar* stringEnd = checkAndSkipString(uriStart, quote);
  7456. if (!stringEnd)
  7457. return;
  7458. stringEnd = skipWhiteSpace(stringEnd);
  7459. if (*stringEnd != ')')
  7460. return;
  7461. start = result = m_currentCharacter = uriStart;
  7462. parseString(result, quote);
  7463. m_currentCharacter = stringEnd + 1;
  7464. m_token = URI;
  7465. } else {
  7466. UChar* stringEnd = uriStart;
  7467. while (isURILetter(*stringEnd)) {
  7468. if (*stringEnd != '\\')
  7469. ++stringEnd;
  7470. else {
  7471. stringEnd = checkAndSkipEscape(stringEnd);
  7472. if (!stringEnd)
  7473. return;
  7474. }
  7475. }
  7476. stringEnd = skipWhiteSpace(stringEnd);
  7477. if (*stringEnd != ')')
  7478. return;
  7479. start = result = m_currentCharacter = uriStart;
  7480. while (isURILetter(*m_currentCharacter)) {
  7481. if (LIKELY(*m_currentCharacter != '\\'))
  7482. *result++ = *m_currentCharacter++;
  7483. else
  7484. parseEscape(result);
  7485. }
  7486. m_currentCharacter = stringEnd + 1;
  7487. m_token = URI;
  7488. }
  7489. }
  7490. inline bool CSSParser::parseUnicodeRange()
  7491. {
  7492. UChar* currentCharacter = m_currentCharacter + 1;
  7493. int length = 6;
  7494. ASSERT(*m_currentCharacter == '+');
  7495. while (isASCIIHexDigit(*currentCharacter) && length) {
  7496. ++currentCharacter;
  7497. --length;
  7498. }
  7499. if (length && *currentCharacter == '?') {
  7500. // At most 5 hex digit followed by a question mark.
  7501. do {
  7502. ++currentCharacter;
  7503. --length;
  7504. } while (*currentCharacter == '?' && length);
  7505. m_currentCharacter = currentCharacter;
  7506. return true;
  7507. }
  7508. if (length < 6) {
  7509. // At least one hex digit.
  7510. if (currentCharacter[0] == '-' && isASCIIHexDigit(currentCharacter[1])) {
  7511. // Followed by a dash and a hex digit.
  7512. ++currentCharacter;
  7513. length = 6;
  7514. do {
  7515. ++currentCharacter;
  7516. } while (--length && isASCIIHexDigit(*currentCharacter));
  7517. }
  7518. m_currentCharacter = currentCharacter;
  7519. return true;
  7520. }
  7521. return false;
  7522. }
  7523. bool CSSParser::parseNthChild()
  7524. {
  7525. UChar* currentCharacter = m_currentCharacter;
  7526. while (isASCIIDigit(*currentCharacter))
  7527. ++currentCharacter;
  7528. if (isASCIIAlphaCaselessEqual(*currentCharacter, 'n')) {
  7529. m_currentCharacter = currentCharacter + 1;
  7530. return true;
  7531. }
  7532. return false;
  7533. }
  7534. bool CSSParser::parseNthChildExtra()
  7535. {
  7536. UChar* currentCharacter = skipWhiteSpace(m_currentCharacter);
  7537. if (*currentCharacter != '+' && *currentCharacter != '-')
  7538. return false;
  7539. currentCharacter = skipWhiteSpace(currentCharacter + 1);
  7540. if (!isASCIIDigit(*currentCharacter))
  7541. return false;
  7542. do {
  7543. ++currentCharacter;
  7544. } while (isASCIIDigit(*currentCharacter));
  7545. m_currentCharacter = currentCharacter;
  7546. return true;
  7547. }
  7548. inline void CSSParser::detectFunctionTypeToken(int length)
  7549. {
  7550. ASSERT(length > 0);
  7551. UChar* name = m_tokenStart;
  7552. switch (length) {
  7553. case 3:
  7554. if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't'))
  7555. m_token = NOTFUNCTION;
  7556. else if (isASCIIAlphaCaselessEqual(name[0], 'u') && isASCIIAlphaCaselessEqual(name[1], 'r') && isASCIIAlphaCaselessEqual(name[2], 'l'))
  7557. m_token = URI;
  7558. return;
  7559. case 9:
  7560. if (isEqualToCSSIdentifier(name, "nth-child"))
  7561. m_parsingMode = NthChildMode;
  7562. return;
  7563. case 11:
  7564. if (isEqualToCSSIdentifier(name, "nth-of-type"))
  7565. m_parsingMode = NthChildMode;
  7566. return;
  7567. case 14:
  7568. if (isEqualToCSSIdentifier(name, "nth-last-child"))
  7569. m_parsingMode = NthChildMode;
  7570. return;
  7571. case 16:
  7572. if (isEqualToCSSIdentifier(name, "nth-last-of-type"))
  7573. m_parsingMode = NthChildMode;
  7574. return;
  7575. }
  7576. }
  7577. inline void CSSParser::detectMediaQueryToken(int length)
  7578. {
  7579. ASSERT(m_parsingMode == MediaQueryMode);
  7580. UChar* name = m_tokenStart;
  7581. if (length == 3) {
  7582. if (isASCIIAlphaCaselessEqual(name[0], 'a') && isASCIIAlphaCaselessEqual(name[1], 'n') && isASCIIAlphaCaselessEqual(name[2], 'd'))
  7583. m_token = MEDIA_AND;
  7584. else if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't'))
  7585. m_token = MEDIA_NOT;
  7586. } else if (length == 4) {
  7587. if (isASCIIAlphaCaselessEqual(name[0], 'o') && isASCIIAlphaCaselessEqual(name[1], 'n')
  7588. && isASCIIAlphaCaselessEqual(name[2], 'l') && isASCIIAlphaCaselessEqual(name[3], 'y'))
  7589. m_token = MEDIA_ONLY;
  7590. }
  7591. }
  7592. inline void CSSParser::detectNumberToken(UChar* type, int length)
  7593. {
  7594. ASSERT(length > 0);
  7595. switch (toASCIILowerUnchecked(type[0])) {
  7596. case 'c':
  7597. if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'm'))
  7598. m_token = CMS;
  7599. return;
  7600. case 'd':
  7601. if (length == 3 && isASCIIAlphaCaselessEqual(type[1], 'e') && isASCIIAlphaCaselessEqual(type[2], 'g'))
  7602. m_token = DEGS;
  7603. #if ENABLE(CSS_IMAGE_RESOLUTION)
  7604. else if (length > 2 && isASCIIAlphaCaselessEqual(type[1], 'p')) {
  7605. if (length == 4) {
  7606. // There is a discussion about the name of this unit on www-style.
  7607. // Keep this compile time guard in place until that is resolved.
  7608. // http://lists.w3.org/Archives/Public/www-style/2012May/0915.html
  7609. if (isASCIIAlphaCaselessEqual(type[2], 'p') && isASCIIAlphaCaselessEqual(type[3], 'x'))
  7610. m_token = DPPX;
  7611. else if (isASCIIAlphaCaselessEqual(type[2], 'c') && isASCIIAlphaCaselessEqual(type[3], 'm'))
  7612. m_token = DPCM;
  7613. } else if (length == 3 && isASCIIAlphaCaselessEqual(type[2], 'i'))
  7614. m_token = DPI;
  7615. }
  7616. #endif
  7617. return;
  7618. case 'e':
  7619. if (length == 2) {
  7620. if (isASCIIAlphaCaselessEqual(type[1], 'm'))
  7621. m_token = EMS;
  7622. else if (isASCIIAlphaCaselessEqual(type[1], 'x'))
  7623. m_token = EXS;
  7624. }
  7625. return;
  7626. case 'g':
  7627. if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'r')
  7628. && isASCIIAlphaCaselessEqual(type[2], 'a') && isASCIIAlphaCaselessEqual(type[3], 'd'))
  7629. m_token = GRADS;
  7630. return;
  7631. case 'h':
  7632. if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'z'))
  7633. m_token = HERTZ;
  7634. return;
  7635. case 'i':
  7636. if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'n'))
  7637. m_token = INS;
  7638. return;
  7639. case 'k':
  7640. if (length == 3 && isASCIIAlphaCaselessEqual(type[1], 'h') && isASCIIAlphaCaselessEqual(type[2], 'z'))
  7641. m_token = KHERTZ;
  7642. return;
  7643. case 'm':
  7644. if (length == 2) {
  7645. if (isASCIIAlphaCaselessEqual(type[1], 'm'))
  7646. m_token = MMS;
  7647. else if (isASCIIAlphaCaselessEqual(type[1], 's'))
  7648. m_token = MSECS;
  7649. }
  7650. return;
  7651. case 'p':
  7652. if (length == 2) {
  7653. if (isASCIIAlphaCaselessEqual(type[1], 'x'))
  7654. m_token = PXS;
  7655. else if (isASCIIAlphaCaselessEqual(type[1], 't'))
  7656. m_token = PTS;
  7657. else if (isASCIIAlphaCaselessEqual(type[1], 'c'))
  7658. m_token = PCS;
  7659. }
  7660. return;
  7661. case 'r':
  7662. if (length == 3) {
  7663. if (isASCIIAlphaCaselessEqual(type[1], 'a') && isASCIIAlphaCaselessEqual(type[2], 'd'))
  7664. m_token = RADS;
  7665. else if (isASCIIAlphaCaselessEqual(type[1], 'e') && isASCIIAlphaCaselessEqual(type[2], 'm'))
  7666. m_token = REMS;
  7667. }
  7668. return;
  7669. case 's':
  7670. if (length == 1)
  7671. m_token = SECS;
  7672. return;
  7673. case 't':
  7674. if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'u')
  7675. && isASCIIAlphaCaselessEqual(type[2], 'r') && isASCIIAlphaCaselessEqual(type[3], 'n'))
  7676. m_token = TURNS;
  7677. return;
  7678. case 'v':
  7679. if (length == 2) {
  7680. if (isASCIIAlphaCaselessEqual(type[1], 'w'))
  7681. m_token = VW;
  7682. else if (isASCIIAlphaCaselessEqual(type[1], 'h'))
  7683. m_token = VH;
  7684. } else if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'm')
  7685. && isASCIIAlphaCaselessEqual(type[2], 'i') && isASCIIAlphaCaselessEqual(type[3], 'n'))
  7686. m_token = VMIN;
  7687. return;
  7688. default:
  7689. if (type[0] == '_' && length == 5 && type[1] == '_' && isASCIIAlphaCaselessEqual(type[2], 'q')
  7690. && isASCIIAlphaCaselessEqual(type[3], 'e') && isASCIIAlphaCaselessEqual(type[4], 'm'))
  7691. m_token = QEMS;
  7692. return;
  7693. }
  7694. }
  7695. inline void CSSParser::detectDashToken(int length)
  7696. {
  7697. UChar* name = m_tokenStart;
  7698. if (length == 11) {
  7699. if (isASCIIAlphaCaselessEqual(name[10], 'y') && isEqualToCSSIdentifier(name + 1, "webkit-an"))
  7700. m_token = ANYFUNCTION;
  7701. else if (isASCIIAlphaCaselessEqual(name[10], 'n') && isEqualToCSSIdentifier(name + 1, "webkit-mi"))
  7702. m_token = MINFUNCTION;
  7703. else if (isASCIIAlphaCaselessEqual(name[10], 'x') && isEqualToCSSIdentifier(name + 1, "webkit-ma"))
  7704. m_token = MAXFUNCTION;
  7705. #if ENABLE(CSS_VARIABLES)
  7706. else if (cssVariablesEnabled() && isASCIIAlphaCaselessEqual(name[10], 'r') && isEqualToCSSIdentifier(name + 1, "webkit-va"))
  7707. m_token = VARFUNCTION;
  7708. #endif
  7709. } else if (length == 12 && isEqualToCSSIdentifier(name + 1, "webkit-calc"))
  7710. m_token = CALCFUNCTION;
  7711. }
  7712. inline void CSSParser::detectAtToken(int length, bool hasEscape)
  7713. {
  7714. UChar* name = m_tokenStart;
  7715. ASSERT(name[0] == '@' && length >= 2);
  7716. // charset, font-face, import, media, namespace, page,
  7717. // -webkit-keyframes, and -webkit-mediaquery are not affected by hasEscape.
  7718. switch (toASCIILowerUnchecked(name[1])) {
  7719. case 'b':
  7720. if (hasEscape)
  7721. return;
  7722. switch (length) {
  7723. case 12:
  7724. if (isEqualToCSSIdentifier(name + 2, "ottom-left"))
  7725. m_token = BOTTOMLEFT_SYM;
  7726. return;
  7727. case 13:
  7728. if (isEqualToCSSIdentifier(name + 2, "ottom-right"))
  7729. m_token = BOTTOMRIGHT_SYM;
  7730. return;
  7731. case 14:
  7732. if (isEqualToCSSIdentifier(name + 2, "ottom-center"))
  7733. m_token = BOTTOMCENTER_SYM;
  7734. return;
  7735. case 19:
  7736. if (isEqualToCSSIdentifier(name + 2, "ottom-left-corner"))
  7737. m_token = BOTTOMLEFTCORNER_SYM;
  7738. return;
  7739. case 20:
  7740. if (isEqualToCSSIdentifier(name + 2, "ottom-right-corner"))
  7741. m_token = BOTTOMRIGHTCORNER_SYM;
  7742. return;
  7743. }
  7744. return;
  7745. case 'c':
  7746. if (length == 8 && isEqualToCSSIdentifier(name + 2, "harset"))
  7747. m_token = CHARSET_SYM;
  7748. return;
  7749. case 'f':
  7750. if (length == 10 && isEqualToCSSIdentifier(name + 2, "ont-face"))
  7751. m_token = FONT_FACE_SYM;
  7752. return;
  7753. case 'i':
  7754. if (length == 7 && isEqualToCSSIdentifier(name + 2, "mport")) {
  7755. m_parsingMode = MediaQueryMode;
  7756. m_token = IMPORT_SYM;
  7757. }
  7758. return;
  7759. case 'l':
  7760. if (hasEscape)
  7761. return;
  7762. if (length == 9) {
  7763. if (isEqualToCSSIdentifier(name + 2, "eft-top"))
  7764. m_token = LEFTTOP_SYM;
  7765. } else if (length == 12) {
  7766. // Checking the last character first could further reduce the possibile cases.
  7767. if (isASCIIAlphaCaselessEqual(name[11], 'e') && isEqualToCSSIdentifier(name + 2, "eft-middl"))
  7768. m_token = LEFTMIDDLE_SYM;
  7769. else if (isASCIIAlphaCaselessEqual(name[11], 'm') && isEqualToCSSIdentifier(name + 2, "eft-botto"))
  7770. m_token = LEFTBOTTOM_SYM;
  7771. }
  7772. return;
  7773. case 'm':
  7774. if (length == 6 && isEqualToCSSIdentifier(name + 2, "edia")) {
  7775. m_parsingMode = MediaQueryMode;
  7776. m_token = MEDIA_SYM;
  7777. }
  7778. return;
  7779. case 'n':
  7780. if (length == 10 && isEqualToCSSIdentifier(name + 2, "amespace"))
  7781. m_token = NAMESPACE_SYM;
  7782. return;
  7783. case 'p':
  7784. if (length == 5 && isEqualToCSSIdentifier(name + 2, "age"))
  7785. m_token = PAGE_SYM;
  7786. return;
  7787. case 'r':
  7788. if (hasEscape)
  7789. return;
  7790. if (length == 10) {
  7791. if (isEqualToCSSIdentifier(name + 2, "ight-top"))
  7792. m_token = RIGHTTOP_SYM;
  7793. } else if (length == 13) {
  7794. // Checking the last character first could further reduce the possibile cases.
  7795. if (isASCIIAlphaCaselessEqual(name[12], 'e') && isEqualToCSSIdentifier(name + 2, "ight-middl"))
  7796. m_token = RIGHTMIDDLE_SYM;
  7797. else if (isASCIIAlphaCaselessEqual(name[12], 'm') && isEqualToCSSIdentifier(name + 2, "ight-botto"))
  7798. m_token = RIGHTBOTTOM_SYM;
  7799. }
  7800. return;
  7801. case 't':
  7802. if (hasEscape)
  7803. return;
  7804. switch (length) {
  7805. case 9:
  7806. if (isEqualToCSSIdentifier(name + 2, "op-left"))
  7807. m_token = TOPLEFT_SYM;
  7808. return;
  7809. case 10:
  7810. if (isEqualToCSSIdentifier(name + 2, "op-right"))
  7811. m_token = TOPRIGHT_SYM;
  7812. return;
  7813. case 11:
  7814. if (isEqualToCSSIdentifier(name + 2, "op-center"))
  7815. m_token = TOPCENTER_SYM;
  7816. return;
  7817. case 16:
  7818. if (isEqualToCSSIdentifier(name + 2, "op-left-corner"))
  7819. m_token = TOPLEFTCORNER_SYM;
  7820. return;
  7821. case 17:
  7822. if (isEqualToCSSIdentifier(name + 2, "op-right-corner"))
  7823. m_token = TOPRIGHTCORNER_SYM;
  7824. return;
  7825. }
  7826. return;
  7827. case '-':
  7828. switch (length) {
  7829. case 13:
  7830. if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-rule"))
  7831. m_token = WEBKIT_RULE_SYM;
  7832. return;
  7833. case 14:
  7834. if (hasEscape)
  7835. return;
  7836. // Checking the last character first could further reduce the possibile cases.
  7837. if (isASCIIAlphaCaselessEqual(name[13], 's') && isEqualToCSSIdentifier(name + 2, "webkit-decl"))
  7838. m_token = WEBKIT_DECLS_SYM;
  7839. else if (isASCIIAlphaCaselessEqual(name[13], 'e') && isEqualToCSSIdentifier(name + 2, "webkit-valu"))
  7840. m_token = WEBKIT_VALUE_SYM;
  7841. return;
  7842. case 15:
  7843. #if ENABLE(CSS_REGIONS)
  7844. if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-region"))
  7845. m_token = WEBKIT_REGION_RULE_SYM;
  7846. #endif
  7847. return;
  7848. case 17:
  7849. if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-selector"))
  7850. m_token = WEBKIT_SELECTOR_SYM;
  7851. return;
  7852. case 18:
  7853. if (isEqualToCSSIdentifier(name + 2, "webkit-keyframes"))
  7854. m_token = WEBKIT_KEYFRAMES_SYM;
  7855. return;
  7856. case 19:
  7857. if (isEqualToCSSIdentifier(name + 2, "webkit-mediaquery")) {
  7858. m_parsingMode = MediaQueryMode;
  7859. m_token = WEBKIT_MEDIAQUERY_SYM;
  7860. }
  7861. return;
  7862. case 22:
  7863. if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-keyframe-rule"))
  7864. m_token = WEBKIT_KEYFRAME_RULE_SYM;
  7865. return;
  7866. }
  7867. }
  7868. }
  7869. int CSSParser::lex(void* yylvalWithoutType)
  7870. {
  7871. YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType);
  7872. // Write pointer for the next character.
  7873. UChar* result;
  7874. bool hasEscape;
  7875. // The input buffer is terminated by a \0 character, so
  7876. // it is safe to read one character ahead of a known non-null.
  7877. #ifndef NDEBUG
  7878. // In debug we check with an ASSERT that the length is > 0 for string types.
  7879. yylval->string.characters = 0;
  7880. yylval->string.length = 0;
  7881. #endif
  7882. restartAfterComment:
  7883. m_tokenStart = result = m_currentCharacter;
  7884. m_token = *m_currentCharacter;
  7885. ++m_currentCharacter;
  7886. switch ((m_token <= 127) ? typesOfASCIICharacters[m_token] : CharacterIdentifierStart) {
  7887. case CharacterCaselessU:
  7888. if (UNLIKELY(*m_currentCharacter == '+'))
  7889. if (parseUnicodeRange()) {
  7890. m_token = UNICODERANGE;
  7891. yylval->string.characters = m_tokenStart;
  7892. yylval->string.length = m_currentCharacter - m_tokenStart;
  7893. break;
  7894. }
  7895. // Fall through to CharacterIdentifierStart.
  7896. case CharacterIdentifierStart:
  7897. --m_currentCharacter;
  7898. parseIdentifier(result, hasEscape);
  7899. m_token = IDENT;
  7900. yylval->string.characters = m_tokenStart;
  7901. yylval->string.length = result - m_tokenStart;
  7902. if (UNLIKELY(*m_currentCharacter == '(')) {
  7903. m_token = FUNCTION;
  7904. if (!hasEscape)
  7905. detectFunctionTypeToken(result - m_tokenStart);
  7906. ++m_currentCharacter;
  7907. ++result;
  7908. ++yylval->string.length;
  7909. if (token() == URI) {
  7910. m_token = FUNCTION;
  7911. // Check whether it is really an URI.
  7912. parseURI(yylval->string.characters, result);
  7913. yylval->string.length = result - yylval->string.characters;
  7914. }
  7915. } else if (UNLIKELY(m_parsingMode != NormalMode) && !hasEscape) {
  7916. if (m_parsingMode == MediaQueryMode)
  7917. detectMediaQueryToken(result - m_tokenStart);
  7918. else if (m_parsingMode == NthChildMode && isASCIIAlphaCaselessEqual(m_tokenStart[0], 'n')) {
  7919. if (result - m_tokenStart == 1) {
  7920. // String "n" is IDENT but "n+1" is NTH.
  7921. if (parseNthChildExtra()) {
  7922. m_token = NTH;
  7923. yylval->string.length = m_currentCharacter - m_tokenStart;
  7924. }
  7925. } else if (result - m_tokenStart >= 2 && m_tokenStart[1] == '-') {
  7926. // String "n-" is IDENT but "n-1" is NTH.
  7927. // Set m_currentCharacter to '-' to continue parsing.
  7928. UChar* nextCharacter = result;
  7929. m_currentCharacter = m_tokenStart + 1;
  7930. if (parseNthChildExtra()) {
  7931. m_token = NTH;
  7932. yylval->string.length = m_currentCharacter - m_tokenStart;
  7933. } else {
  7934. // Revert the change to m_currentCharacter if unsuccessful.
  7935. m_currentCharacter = nextCharacter;
  7936. }
  7937. }
  7938. }
  7939. }
  7940. break;
  7941. case CharacterDot:
  7942. if (!isASCIIDigit(m_currentCharacter[0]))
  7943. break;
  7944. // Fall through to CharacterNumber.
  7945. case CharacterNumber: {
  7946. bool dotSeen = (m_token == '.');
  7947. while (true) {
  7948. if (!isASCIIDigit(m_currentCharacter[0])) {
  7949. // Only one dot is allowed for a number,
  7950. // and it must be followed by a digit.
  7951. if (m_currentCharacter[0] != '.' || dotSeen || !isASCIIDigit(m_currentCharacter[1]))
  7952. break;
  7953. dotSeen = true;
  7954. }
  7955. ++m_currentCharacter;
  7956. }
  7957. if (UNLIKELY(m_parsingMode == NthChildMode) && !dotSeen && isASCIIAlphaCaselessEqual(*m_currentCharacter, 'n')) {
  7958. // "[0-9]+n" is always an NthChild.
  7959. ++m_currentCharacter;
  7960. parseNthChildExtra();
  7961. m_token = NTH;
  7962. yylval->string.characters = m_tokenStart;
  7963. yylval->string.length = m_currentCharacter - m_tokenStart;
  7964. break;
  7965. }
  7966. #if ENABLE(SVG)
  7967. // Use SVG parser for numbers on SVG presentation attributes.
  7968. if (m_context.mode == SVGAttributeMode) {
  7969. // We need to take care of units like 'em' or 'ex'.
  7970. UChar* currentCharacter = m_currentCharacter;
  7971. if (isASCIIAlphaCaselessEqual(*currentCharacter, 'e')) {
  7972. ASSERT(currentCharacter - m_tokenStart > 0);
  7973. ++currentCharacter;
  7974. if (*currentCharacter == '-' || *currentCharacter == '+' || isASCIIDigit(*currentCharacter)) {
  7975. ++currentCharacter;
  7976. while (isASCIIDigit(*currentCharacter))
  7977. ++currentCharacter;
  7978. // Use FLOATTOKEN if the string contains exponents.
  7979. dotSeen = true;
  7980. m_currentCharacter = currentCharacter;
  7981. }
  7982. }
  7983. if (!parseSVGNumber(m_tokenStart, currentCharacter - m_tokenStart, yylval->number))
  7984. break;
  7985. } else
  7986. #endif
  7987. yylval->number = charactersToDouble(m_tokenStart, m_currentCharacter - m_tokenStart);
  7988. // Type of the function.
  7989. if (isIdentifierStart()) {
  7990. UChar* type = m_currentCharacter;
  7991. result = m_currentCharacter;
  7992. parseIdentifier(result, hasEscape);
  7993. if (*m_currentCharacter == '+') {
  7994. // Any identifier followed by a '+' sign is an invalid dimension.
  7995. ++m_currentCharacter;
  7996. m_token = INVALIDDIMEN;
  7997. } else {
  7998. m_token = DIMEN;
  7999. if (!hasEscape)
  8000. detectNumberToken(type, m_currentCharacter - type);
  8001. if (m_token == DIMEN) {
  8002. // The decoded number is overwritten, but this is intentional.
  8003. yylval->string.characters = m_tokenStart;
  8004. yylval->string.length = m_currentCharacter - m_tokenStart;
  8005. }
  8006. }
  8007. } else if (*m_currentCharacter == '%') {
  8008. // Although the CSS grammar says {num}% we follow
  8009. // webkit at the moment which uses {num}%+.
  8010. do {
  8011. ++m_currentCharacter;
  8012. } while (*m_currentCharacter == '%');
  8013. m_token = PERCENTAGE;
  8014. } else
  8015. m_token = dotSeen ? FLOATTOKEN : INTEGER;
  8016. break;
  8017. }
  8018. case CharacterDash:
  8019. if (isIdentifierStartAfterDash(m_currentCharacter)) {
  8020. --m_currentCharacter;
  8021. parseIdentifier(result, hasEscape);
  8022. m_token = IDENT;
  8023. #if ENABLE(CSS_VARIABLES)
  8024. if (cssVariablesEnabled() && isEqualToCSSIdentifier(m_tokenStart + 1, "webkit-var") && m_tokenStart[11] == '-' && isIdentifierStartAfterDash(m_tokenStart + 12))
  8025. m_token = VAR_DEFINITION;
  8026. else
  8027. #endif
  8028. if (*m_currentCharacter == '(') {
  8029. m_token = FUNCTION;
  8030. if (!hasEscape)
  8031. detectDashToken(result - m_tokenStart);
  8032. ++m_currentCharacter;
  8033. ++result;
  8034. } else if (UNLIKELY(m_parsingMode == NthChildMode) && !hasEscape && isASCIIAlphaCaselessEqual(m_tokenStart[1], 'n')) {
  8035. if (result - m_tokenStart == 2) {
  8036. // String "-n" is IDENT but "-n+1" is NTH.
  8037. if (parseNthChildExtra()) {
  8038. m_token = NTH;
  8039. result = m_currentCharacter;
  8040. }
  8041. } else if (result - m_tokenStart >= 3 && m_tokenStart[2] == '-') {
  8042. // String "-n-" is IDENT but "-n-1" is NTH.
  8043. // Set m_currentCharacter to second '-' of '-n-' to continue parsing.
  8044. UChar* nextCharacter = result;
  8045. m_currentCharacter = m_tokenStart + 2;
  8046. if (parseNthChildExtra()) {
  8047. m_token = NTH;
  8048. result = m_currentCharacter;
  8049. } else {
  8050. // Revert the change to m_currentCharacter if unsuccessful.
  8051. m_currentCharacter = nextCharacter;
  8052. }
  8053. }
  8054. }
  8055. yylval->string.characters = m_tokenStart;
  8056. yylval->string.length = result - m_tokenStart;
  8057. } else if (m_currentCharacter[0] == '-' && m_currentCharacter[1] == '>') {
  8058. m_currentCharacter += 2;
  8059. m_token = SGML_CD;
  8060. } else if (UNLIKELY(m_parsingMode == NthChildMode)) {
  8061. // "-[0-9]+n" is always an NthChild.
  8062. if (parseNthChild()) {
  8063. parseNthChildExtra();
  8064. m_token = NTH;
  8065. yylval->string.characters = m_tokenStart;
  8066. yylval->string.length = m_currentCharacter - m_tokenStart;
  8067. }
  8068. }
  8069. break;
  8070. case CharacterOther:
  8071. // m_token is simply the current character.
  8072. break;
  8073. case CharacterNull:
  8074. // Do not advance pointer at the end of input.
  8075. --m_currentCharacter;
  8076. break;
  8077. case CharacterWhiteSpace:
  8078. m_token = WHITESPACE;
  8079. // Might start with a '\n'.
  8080. --m_currentCharacter;
  8081. do {
  8082. if (*m_currentCharacter == '\n')
  8083. ++m_lineNumber;
  8084. ++m_currentCharacter;
  8085. } while (*m_currentCharacter <= ' ' && (typesOfASCIICharacters[*m_currentCharacter] == CharacterWhiteSpace));
  8086. break;
  8087. case CharacterEndMediaQuery:
  8088. if (m_parsingMode == MediaQueryMode)
  8089. m_parsingMode = NormalMode;
  8090. break;
  8091. case CharacterEndNthChild:
  8092. if (m_parsingMode == NthChildMode)
  8093. m_parsingMode = NormalMode;
  8094. break;
  8095. case CharacterQuote:
  8096. if (checkAndSkipString(m_currentCharacter, m_token)) {
  8097. ++result;
  8098. parseString(result, m_token);
  8099. m_token = STRING;
  8100. yylval->string.characters = m_tokenStart + 1;
  8101. yylval->string.length = result - (m_tokenStart + 1);
  8102. }
  8103. break;
  8104. case CharacterExclamationMark: {
  8105. UChar* start = skipWhiteSpace(m_currentCharacter);
  8106. if (isEqualToCSSIdentifier(start, "important")) {
  8107. m_token = IMPORTANT_SYM;
  8108. m_currentCharacter = start + 9;
  8109. }
  8110. break;
  8111. }
  8112. case CharacterHashmark: {
  8113. UChar* start = m_currentCharacter;
  8114. result = m_currentCharacter;
  8115. if (isASCIIDigit(*m_currentCharacter)) {
  8116. // This must be a valid hex number token.
  8117. do {
  8118. ++m_currentCharacter;
  8119. } while (isASCIIHexDigit(*m_currentCharacter));
  8120. m_token = HEX;
  8121. yylval->string.characters = start;
  8122. yylval->string.length = m_currentCharacter - start;
  8123. } else if (isIdentifierStart()) {
  8124. m_token = IDSEL;
  8125. parseIdentifier(result, hasEscape);
  8126. if (!hasEscape) {
  8127. // Check whether the identifier is also a valid hex number.
  8128. UChar* current = start;
  8129. m_token = HEX;
  8130. do {
  8131. if (!isASCIIHexDigit(*current)) {
  8132. m_token = IDSEL;
  8133. break;
  8134. }
  8135. ++current;
  8136. } while (current < result);
  8137. }
  8138. yylval->string.characters = start;
  8139. yylval->string.length = result - start;
  8140. }
  8141. break;
  8142. }
  8143. case CharacterSlash:
  8144. // Ignore comments. They are not even considered as white spaces.
  8145. if (*m_currentCharacter == '*') {
  8146. ++m_currentCharacter;
  8147. while (m_currentCharacter[0] != '*' || m_currentCharacter[1] != '/') {
  8148. if (*m_currentCharacter == '\n')
  8149. ++m_lineNumber;
  8150. if (*m_currentCharacter == '\0') {
  8151. // Unterminated comments are simply ignored.
  8152. m_currentCharacter -= 2;
  8153. break;
  8154. }
  8155. ++m_currentCharacter;
  8156. }
  8157. m_currentCharacter += 2;
  8158. goto restartAfterComment;
  8159. }
  8160. break;
  8161. case CharacterDollar:
  8162. if (*m_currentCharacter == '=') {
  8163. ++m_currentCharacter;
  8164. m_token = ENDSWITH;
  8165. }
  8166. break;
  8167. case CharacterAsterisk:
  8168. if (*m_currentCharacter == '=') {
  8169. ++m_currentCharacter;
  8170. m_token = CONTAINS;
  8171. }
  8172. break;
  8173. case CharacterPlus:
  8174. if (UNLIKELY(m_parsingMode == NthChildMode)) {
  8175. // Simplest case. "+[0-9]*n" is always NthChild.
  8176. if (parseNthChild()) {
  8177. parseNthChildExtra();
  8178. m_token = NTH;
  8179. yylval->string.characters = m_tokenStart;
  8180. yylval->string.length = m_currentCharacter - m_tokenStart;
  8181. }
  8182. }
  8183. break;
  8184. case CharacterLess:
  8185. if (m_currentCharacter[0] == '!' && m_currentCharacter[1] == '-' && m_currentCharacter[2] == '-') {
  8186. m_currentCharacter += 3;
  8187. m_token = SGML_CD;
  8188. }
  8189. break;
  8190. case CharacterAt:
  8191. if (isIdentifierStart()) {
  8192. m_token = ATKEYWORD;
  8193. ++result;
  8194. parseIdentifier(result, hasEscape);
  8195. detectAtToken(result - m_tokenStart, hasEscape);
  8196. }
  8197. break;
  8198. case CharacterBackSlash:
  8199. if (isCSSEscape(*m_currentCharacter)) {
  8200. --m_currentCharacter;
  8201. parseIdentifier(result, hasEscape);
  8202. m_token = IDENT;
  8203. yylval->string.characters = m_tokenStart;
  8204. yylval->string.length = result - m_tokenStart;
  8205. }
  8206. break;
  8207. case CharacterXor:
  8208. if (*m_currentCharacter == '=') {
  8209. ++m_currentCharacter;
  8210. m_token = BEGINSWITH;
  8211. }
  8212. break;
  8213. case CharacterVerticalBar:
  8214. if (*m_currentCharacter == '=') {
  8215. ++m_currentCharacter;
  8216. m_token = DASHMATCH;
  8217. }
  8218. break;
  8219. case CharacterTilde:
  8220. if (*m_currentCharacter == '=') {
  8221. ++m_currentCharacter;
  8222. m_token = INCLUDES;
  8223. }
  8224. break;
  8225. default:
  8226. ASSERT_NOT_REACHED();
  8227. break;
  8228. }
  8229. #ifndef NDEBUG
  8230. switch (token()) {
  8231. case STRING:
  8232. ASSERT(yylval->string.characters == m_tokenStart + 1);
  8233. break;
  8234. case IDENT:
  8235. case NTH:
  8236. case DIMEN:
  8237. case UNICODERANGE:
  8238. case FUNCTION:
  8239. case ANYFUNCTION:
  8240. case NOTFUNCTION:
  8241. case CALCFUNCTION:
  8242. case MINFUNCTION:
  8243. case MAXFUNCTION:
  8244. ASSERT(yylval->string.characters == m_tokenStart && yylval->string.length > 0);
  8245. break;
  8246. case URI:
  8247. ASSERT(yylval->string.characters && yylval->string.characters != m_tokenStart);
  8248. break;
  8249. case HEX:
  8250. case IDSEL:
  8251. ASSERT(yylval->string.characters == m_tokenStart + 1 && yylval->string.length > 0);
  8252. break;
  8253. }
  8254. #endif
  8255. return token();
  8256. }
  8257. CSSParserSelector* CSSParser::createFloatingSelector()
  8258. {
  8259. CSSParserSelector* selector = new CSSParserSelector;
  8260. m_floatingSelectors.add(selector);
  8261. return selector;
  8262. }
  8263. PassOwnPtr<CSSParserSelector> CSSParser::sinkFloatingSelector(CSSParserSelector* selector)
  8264. {
  8265. if (selector) {
  8266. ASSERT(m_floatingSelectors.contains(selector));
  8267. m_floatingSelectors.remove(selector);
  8268. }
  8269. return adoptPtr(selector);
  8270. }
  8271. Vector<OwnPtr<CSSParserSelector> >* CSSParser::createFloatingSelectorVector()
  8272. {
  8273. Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >;
  8274. m_floatingSelectorVectors.add(selectorVector);
  8275. return selectorVector;
  8276. }
  8277. PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > CSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector)
  8278. {
  8279. if (selectorVector) {
  8280. ASSERT(m_floatingSelectorVectors.contains(selectorVector));
  8281. m_floatingSelectorVectors.remove(selectorVector);
  8282. }
  8283. return adoptPtr(selectorVector);
  8284. }
  8285. CSSParserValueList* CSSParser::createFloatingValueList()
  8286. {
  8287. CSSParserValueList* list = new CSSParserValueList;
  8288. m_floatingValueLists.add(list);
  8289. return list;
  8290. }
  8291. PassOwnPtr<CSSParserValueList> CSSParser::sinkFloatingValueList(CSSParserValueList* list)
  8292. {
  8293. if (list) {
  8294. ASSERT(m_floatingValueLists.contains(list));
  8295. m_floatingValueLists.remove(list);
  8296. }
  8297. return adoptPtr(list);
  8298. }
  8299. CSSParserFunction* CSSParser::createFloatingFunction()
  8300. {
  8301. CSSParserFunction* function = new CSSParserFunction;
  8302. m_floatingFunctions.add(function);
  8303. return function;
  8304. }
  8305. PassOwnPtr<CSSParserFunction> CSSParser::sinkFloatingFunction(CSSParserFunction* function)
  8306. {
  8307. if (function) {
  8308. ASSERT(m_floatingFunctions.contains(function));
  8309. m_floatingFunctions.remove(function);
  8310. }
  8311. return adoptPtr(function);
  8312. }
  8313. CSSParserValue& CSSParser::sinkFloatingValue(CSSParserValue& value)
  8314. {
  8315. if (value.unit == CSSParserValue::Function) {
  8316. ASSERT(m_floatingFunctions.contains(value.function));
  8317. m_floatingFunctions.remove(value.function);
  8318. }
  8319. return value;
  8320. }
  8321. MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
  8322. {
  8323. m_floatingMediaQueryExp = MediaQueryExp::create(mediaFeature, values);
  8324. return m_floatingMediaQueryExp.get();
  8325. }
  8326. PassOwnPtr<MediaQueryExp> CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression)
  8327. {
  8328. ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp);
  8329. return m_floatingMediaQueryExp.release();
  8330. }
  8331. Vector<OwnPtr<MediaQueryExp> >* CSSParser::createFloatingMediaQueryExpList()
  8332. {
  8333. m_floatingMediaQueryExpList = adoptPtr(new Vector<OwnPtr<MediaQueryExp> >);
  8334. return m_floatingMediaQueryExpList.get();
  8335. }
  8336. PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > CSSParser::sinkFloatingMediaQueryExpList(Vector<OwnPtr<MediaQueryExp> >* list)
  8337. {
  8338. ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList);
  8339. return m_floatingMediaQueryExpList.release();
  8340. }
  8341. MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const String& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
  8342. {
  8343. m_floatingMediaQuery = adoptPtr(new MediaQuery(restrictor, mediaType, expressions));
  8344. return m_floatingMediaQuery.get();
  8345. }
  8346. MediaQuery* CSSParser::createFloatingMediaQuery(PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
  8347. {
  8348. return createFloatingMediaQuery(MediaQuery::None, "all", expressions);
  8349. }
  8350. PassOwnPtr<MediaQuery> CSSParser::sinkFloatingMediaQuery(MediaQuery* query)
  8351. {
  8352. ASSERT_UNUSED(query, query == m_floatingMediaQuery);
  8353. return m_floatingMediaQuery.release();
  8354. }
  8355. Vector<RefPtr<StyleKeyframe> >* CSSParser::createFloatingKeyframeVector()
  8356. {
  8357. m_floatingKeyframeVector = adoptPtr(new Vector<RefPtr<StyleKeyframe> >());
  8358. return m_floatingKeyframeVector.get();
  8359. }
  8360. PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > CSSParser::sinkFloatingKeyframeVector(Vector<RefPtr<StyleKeyframe> >* keyframeVector)
  8361. {
  8362. ASSERT_UNUSED(keyframeVector, m_floatingKeyframeVector == keyframeVector);
  8363. return m_floatingKeyframeVector.release();
  8364. }
  8365. MediaQuerySet* CSSParser::createMediaQuerySet()
  8366. {
  8367. RefPtr<MediaQuerySet> queries = MediaQuerySet::create();
  8368. MediaQuerySet* result = queries.get();
  8369. m_parsedMediaQuerySets.append(queries.release());
  8370. return result;
  8371. }
  8372. StyleRuleBase* CSSParser::createImportRule(const CSSParserString& url, MediaQuerySet* media)
  8373. {
  8374. if (!media || !m_allowImportRules)
  8375. return 0;
  8376. RefPtr<StyleRuleImport> rule = StyleRuleImport::create(url, media);
  8377. StyleRuleImport* result = rule.get();
  8378. m_parsedRules.append(rule.release());
  8379. processAndAddNewRuleToSourceTreeIfNeeded();
  8380. return result;
  8381. }
  8382. StyleRuleBase* CSSParser::createMediaRule(MediaQuerySet* media, RuleList* rules)
  8383. {
  8384. m_allowImportRules = m_allowNamespaceDeclarations = false;
  8385. RefPtr<StyleRuleMedia> rule;
  8386. if (rules)
  8387. rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), *rules);
  8388. else {
  8389. RuleList emptyRules;
  8390. rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), emptyRules);
  8391. }
  8392. StyleRuleMedia* result = rule.get();
  8393. m_parsedRules.append(rule.release());
  8394. processAndAddNewRuleToSourceTreeIfNeeded();
  8395. return result;
  8396. }
  8397. CSSParser::RuleList* CSSParser::createRuleList()
  8398. {
  8399. OwnPtr<RuleList> list = adoptPtr(new RuleList);
  8400. RuleList* listPtr = list.get();
  8401. m_parsedRuleLists.append(list.release());
  8402. return listPtr;
  8403. }
  8404. void CSSParser::processAndAddNewRuleToSourceTreeIfNeeded()
  8405. {
  8406. if (!isExtractingSourceData())
  8407. return;
  8408. markRuleBodyEnd();
  8409. RefPtr<CSSRuleSourceData> rule = popRuleData();
  8410. fixUnparsedPropertyRanges(rule.get());
  8411. addNewRuleToSourceTree(rule.release());
  8412. }
  8413. void CSSParser::addNewRuleToSourceTree(PassRefPtr<CSSRuleSourceData> rule)
  8414. {
  8415. // Precondition: (isExtractingSourceData()).
  8416. if (!m_ruleSourceDataResult)
  8417. return;
  8418. if (m_currentRuleDataStack->isEmpty())
  8419. m_ruleSourceDataResult->append(rule);
  8420. else
  8421. m_currentRuleDataStack->last()->childRules.append(rule);
  8422. }
  8423. PassRefPtr<CSSRuleSourceData> CSSParser::popRuleData()
  8424. {
  8425. if (!m_ruleSourceDataResult)
  8426. return 0;
  8427. ASSERT(!m_currentRuleDataStack->isEmpty());
  8428. RefPtr<CSSRuleSourceData> data = m_currentRuleDataStack->last();
  8429. m_currentRuleDataStack->removeLast();
  8430. return data.release();
  8431. }
  8432. StyleRuleKeyframes* CSSParser::createKeyframesRule(const String& name, PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > popKeyframes)
  8433. {
  8434. OwnPtr<Vector<RefPtr<StyleKeyframe> > > keyframes = popKeyframes;
  8435. m_allowImportRules = m_allowNamespaceDeclarations = false;
  8436. RefPtr<StyleRuleKeyframes> rule = StyleRuleKeyframes::create();
  8437. for (size_t i = 0; i < keyframes->size(); ++i)
  8438. rule->parserAppendKeyframe(keyframes->at(i));
  8439. rule->setName(name);
  8440. StyleRuleKeyframes* rulePtr = rule.get();
  8441. m_parsedRules.append(rule.release());
  8442. processAndAddNewRuleToSourceTreeIfNeeded();
  8443. return rulePtr;
  8444. }
  8445. StyleRuleBase* CSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors)
  8446. {
  8447. StyleRule* result = 0;
  8448. if (selectors) {
  8449. m_allowImportRules = m_allowNamespaceDeclarations = false;
  8450. RefPtr<StyleRule> rule = StyleRule::create(m_lastSelectorLineNumber);
  8451. rule->parserAdoptSelectorVector(*selectors);
  8452. if (m_hasFontFaceOnlyValues)
  8453. deleteFontFaceOnlyValues();
  8454. rule->setProperties(createStylePropertySet());
  8455. result = rule.get();
  8456. m_parsedRules.append(rule.release());
  8457. processAndAddNewRuleToSourceTreeIfNeeded();
  8458. }
  8459. clearProperties();
  8460. return result;
  8461. }
  8462. StyleRuleBase* CSSParser::createFontFaceRule()
  8463. {
  8464. m_allowImportRules = m_allowNamespaceDeclarations = false;
  8465. for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
  8466. CSSProperty& property = m_parsedProperties[i];
  8467. if (property.id() == CSSPropertyFontVariant && property.value()->isPrimitiveValue())
  8468. property.wrapValueInCommaSeparatedList();
  8469. else if (property.id() == CSSPropertyFontFamily && (!property.value()->isValueList() || static_cast<CSSValueList*>(property.value())->length() != 1)) {
  8470. // Unlike font-family property, font-family descriptor in @font-face rule
  8471. // has to be a value list with exactly one family name. It cannot have a
  8472. // have 'initial' value and cannot 'inherit' from parent.
  8473. // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
  8474. clearProperties();
  8475. return 0;
  8476. }
  8477. }
  8478. RefPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create();
  8479. rule->setProperties(createStylePropertySet());
  8480. clearProperties();
  8481. StyleRuleFontFace* result = rule.get();
  8482. m_parsedRules.append(rule.release());
  8483. processAndAddNewRuleToSourceTreeIfNeeded();
  8484. return result;
  8485. }
  8486. void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
  8487. {
  8488. if (!m_styleSheet || !m_allowNamespaceDeclarations)
  8489. return;
  8490. m_allowImportRules = false;
  8491. m_styleSheet->parserAddNamespace(prefix, uri);
  8492. if (prefix.isEmpty() && !uri.isNull())
  8493. m_defaultNamespace = uri;
  8494. }
  8495. QualifiedName CSSParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName)
  8496. {
  8497. if (!m_styleSheet)
  8498. return QualifiedName(prefix, localName, m_defaultNamespace);
  8499. return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix));
  8500. }
  8501. void CSSParser::updateSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers)
  8502. {
  8503. AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
  8504. QualifiedName tag = QualifiedName(namespacePrefix, elementName, determinedNamespace);
  8505. if (!specifiers->isUnknownPseudoElement()) {
  8506. specifiers->setTag(tag);
  8507. return;
  8508. }
  8509. CSSParserSelector* lastShadowDescendant = specifiers;
  8510. CSSParserSelector* history = specifiers;
  8511. while (history->tagHistory()) {
  8512. history = history->tagHistory();
  8513. if (history->isUnknownPseudoElement() || history->hasShadowDescendant())
  8514. lastShadowDescendant = history;
  8515. }
  8516. if (lastShadowDescendant->tagHistory()) {
  8517. lastShadowDescendant->tagHistory()->setTag(tag);
  8518. return;
  8519. }
  8520. // For shadow-ID pseudo-elements to be correctly matched, the ShadowDescendant combinator has to be used.
  8521. // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
  8522. OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector);
  8523. elementNameSelector->setTag(tag);
  8524. lastShadowDescendant->setTagHistory(elementNameSelector.release());
  8525. lastShadowDescendant->setRelation(CSSSelector::ShadowDescendant);
  8526. }
  8527. CSSParserSelector* CSSParser::updateSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier)
  8528. {
  8529. if (newSpecifier->isUnknownPseudoElement()) {
  8530. // Unknown pseudo element always goes at the top of selector chain.
  8531. newSpecifier->appendTagHistory(CSSSelector::ShadowDescendant, sinkFloatingSelector(specifiers));
  8532. return newSpecifier;
  8533. }
  8534. if (specifiers->isUnknownPseudoElement()) {
  8535. // Specifiers for unknown pseudo element go right behind it in the chain.
  8536. specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::ShadowDescendant);
  8537. return specifiers;
  8538. }
  8539. specifiers->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier));
  8540. return specifiers;
  8541. }
  8542. StyleRuleBase* CSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector)
  8543. {
  8544. // FIXME: Margin at-rules are ignored.
  8545. m_allowImportRules = m_allowNamespaceDeclarations = false;
  8546. StyleRulePage* pageRule = 0;
  8547. if (pageSelector) {
  8548. RefPtr<StyleRulePage> rule = StyleRulePage::create();
  8549. Vector<OwnPtr<CSSParserSelector> > selectorVector;
  8550. selectorVector.append(pageSelector);
  8551. rule->parserAdoptSelectorVector(selectorVector);
  8552. rule->setProperties(createStylePropertySet());
  8553. pageRule = rule.get();
  8554. m_parsedRules.append(rule.release());
  8555. processAndAddNewRuleToSourceTreeIfNeeded();
  8556. }
  8557. clearProperties();
  8558. return pageRule;
  8559. }
  8560. void CSSParser::setReusableRegionSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectors)
  8561. {
  8562. if (selectors)
  8563. m_reusableRegionSelectorVector.swap(*selectors);
  8564. }
  8565. StyleRuleBase* CSSParser::createRegionRule(Vector<OwnPtr<CSSParserSelector> >* regionSelector, RuleList* rules)
  8566. {
  8567. if (!cssRegionsEnabled() || !regionSelector || !rules)
  8568. return 0;
  8569. m_allowImportRules = m_allowNamespaceDeclarations = false;
  8570. RefPtr<StyleRuleRegion> regionRule = StyleRuleRegion::create(regionSelector, *rules);
  8571. StyleRuleRegion* result = regionRule.get();
  8572. m_parsedRules.append(regionRule.release());
  8573. if (isExtractingSourceData())
  8574. addNewRuleToSourceTree(CSSRuleSourceData::createUnknown());
  8575. return result;
  8576. }
  8577. StyleRuleBase* CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
  8578. {
  8579. // FIXME: Implement margin at-rule here, using:
  8580. // - marginBox: margin box
  8581. // - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_parsedProperties.size()] are for this at-rule.
  8582. // Don't forget to also update the action for page symbol in CSSGrammar.y such that margin at-rule data is cleared if page_selector is invalid.
  8583. endDeclarationsForMarginBox();
  8584. return 0; // until this method is implemented.
  8585. }
  8586. void CSSParser::startDeclarationsForMarginBox()
  8587. {
  8588. m_numParsedPropertiesBeforeMarginBox = m_parsedProperties.size();
  8589. }
  8590. void CSSParser::endDeclarationsForMarginBox()
  8591. {
  8592. rollbackLastProperties(m_parsedProperties.size() - m_numParsedPropertiesBeforeMarginBox);
  8593. m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
  8594. }
  8595. void CSSParser::deleteFontFaceOnlyValues()
  8596. {
  8597. ASSERT(m_hasFontFaceOnlyValues);
  8598. for (unsigned i = 0; i < m_parsedProperties.size();) {
  8599. CSSProperty& property = m_parsedProperties[i];
  8600. if (property.id() == CSSPropertyFontVariant && property.value()->isValueList()) {
  8601. m_parsedProperties.remove(i);
  8602. continue;
  8603. }
  8604. ++i;
  8605. }
  8606. }
  8607. StyleKeyframe* CSSParser::createKeyframe(CSSParserValueList* keys)
  8608. {
  8609. // Create a key string from the passed keys
  8610. String keyString;
  8611. for (unsigned i = 0; i < keys->size(); ++i) {
  8612. float key = static_cast<float>(keys->valueAt(i)->fValue);
  8613. if (i != 0)
  8614. keyString += ",";
  8615. keyString += String::number(key);
  8616. keyString += "%";
  8617. }
  8618. RefPtr<StyleKeyframe> keyframe = StyleKeyframe::create();
  8619. keyframe->setKeyText(keyString);
  8620. keyframe->setProperties(createStylePropertySet());
  8621. clearProperties();
  8622. StyleKeyframe* keyframePtr = keyframe.get();
  8623. m_parsedKeyframes.append(keyframe.release());
  8624. return keyframePtr;
  8625. }
  8626. void CSSParser::invalidBlockHit()
  8627. {
  8628. if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
  8629. m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
  8630. }
  8631. void CSSParser::updateLastSelectorLineAndPosition()
  8632. {
  8633. m_lastSelectorLineNumber = m_lineNumber;
  8634. markRuleBodyStart();
  8635. }
  8636. void CSSParser::updateLastMediaLine(MediaQuerySet* media)
  8637. {
  8638. media->setLastLine(m_lineNumber);
  8639. }
  8640. void CSSParser::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData)
  8641. {
  8642. if (!ruleData->styleSourceData)
  8643. return;
  8644. Vector<CSSPropertySourceData>& propertyData = ruleData->styleSourceData->propertyData;
  8645. unsigned size = propertyData.size();
  8646. if (!size)
  8647. return;
  8648. unsigned styleStart = ruleData->ruleBodyRange.start;
  8649. const UChar* characters = m_dataStart.get() + m_parsedTextPrefixLength;
  8650. CSSPropertySourceData* nextData = &(propertyData.at(0));
  8651. for (unsigned i = 0; i < size; ++i) {
  8652. CSSPropertySourceData* currentData = nextData;
  8653. nextData = i < size - 1 ? &(propertyData.at(i + 1)) : 0;
  8654. if (currentData->parsedOk)
  8655. continue;
  8656. if (currentData->range.end > 0 && characters[styleStart + currentData->range.end - 1] == ';')
  8657. continue;
  8658. unsigned propertyEndInStyleSheet;
  8659. if (!nextData)
  8660. propertyEndInStyleSheet = ruleData->ruleBodyRange.end - 1;
  8661. else
  8662. propertyEndInStyleSheet = styleStart + nextData->range.start - 1;
  8663. while (isHTMLSpace(characters[propertyEndInStyleSheet]))
  8664. --propertyEndInStyleSheet;
  8665. // propertyEndInStyleSheet points at the last property text character.
  8666. unsigned newPropertyEnd = propertyEndInStyleSheet - styleStart + 1; // Exclusive of the last property text character.
  8667. if (currentData->range.end != newPropertyEnd) {
  8668. currentData->range.end = newPropertyEnd;
  8669. unsigned valueStartInStyleSheet = styleStart + currentData->range.start + currentData->name.length();
  8670. while (valueStartInStyleSheet < propertyEndInStyleSheet && characters[valueStartInStyleSheet] != ':')
  8671. ++valueStartInStyleSheet;
  8672. if (valueStartInStyleSheet < propertyEndInStyleSheet)
  8673. ++valueStartInStyleSheet; // Shift past the ':'.
  8674. while (valueStartInStyleSheet < propertyEndInStyleSheet && isHTMLSpace(characters[valueStartInStyleSheet]))
  8675. ++valueStartInStyleSheet;
  8676. // Need to exclude the trailing ';' from the property value.
  8677. currentData->value = String(characters + valueStartInStyleSheet, propertyEndInStyleSheet - valueStartInStyleSheet + (characters[propertyEndInStyleSheet] == ';' ? 0 : 1));
  8678. }
  8679. }
  8680. }
  8681. void CSSParser::markRuleHeaderStart(CSSRuleSourceData::Type ruleType)
  8682. {
  8683. if (!isExtractingSourceData())
  8684. return;
  8685. RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(ruleType);
  8686. data->ruleHeaderRange.start = m_tokenStart - m_dataStart.get();
  8687. m_currentRuleDataStack->append(data.release());
  8688. }
  8689. void CSSParser::markRuleHeaderEnd()
  8690. {
  8691. if (!isExtractingSourceData())
  8692. return;
  8693. ASSERT(!m_currentRuleDataStack->isEmpty());
  8694. UChar* listEnd = m_tokenStart;
  8695. while (listEnd > m_dataStart.get() + 1) {
  8696. if (isHTMLSpace(*(listEnd - 1)))
  8697. --listEnd;
  8698. else
  8699. break;
  8700. }
  8701. m_currentRuleDataStack->last()->ruleHeaderRange.end = listEnd - m_dataStart.get();
  8702. }
  8703. void CSSParser::markRuleBodyStart()
  8704. {
  8705. if (!isExtractingSourceData())
  8706. return;
  8707. unsigned offset = m_tokenStart - m_dataStart.get();
  8708. if (*m_tokenStart == '{')
  8709. ++offset; // Skip the rule body opening brace.
  8710. ASSERT(!m_currentRuleDataStack->isEmpty());
  8711. m_currentRuleDataStack->last()->ruleBodyRange.start = offset;
  8712. }
  8713. void CSSParser::markRuleBodyEnd()
  8714. {
  8715. // Precondition: (!isExtractingSourceData())
  8716. unsigned offset = m_tokenStart - m_dataStart.get();
  8717. ASSERT(!m_currentRuleDataStack->isEmpty());
  8718. m_currentRuleDataStack->last()->ruleBodyRange.end = offset;
  8719. }
  8720. void CSSParser::markPropertyStart()
  8721. {
  8722. if (!isExtractingSourceData())
  8723. return;
  8724. if (m_currentRuleDataStack->isEmpty() || !m_currentRuleDataStack->last()->styleSourceData)
  8725. return;
  8726. m_propertyRange.start = m_tokenStart - m_dataStart.get();
  8727. }
  8728. void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed)
  8729. {
  8730. if (!isExtractingSourceData())
  8731. return;
  8732. if (m_currentRuleDataStack->isEmpty() || !m_currentRuleDataStack->last()->styleSourceData)
  8733. return;
  8734. unsigned offset = m_tokenStart - m_dataStart.get();
  8735. if (*m_tokenStart == ';') // Include semicolon into the property text.
  8736. ++offset;
  8737. m_propertyRange.end = offset;
  8738. if (m_propertyRange.start != UINT_MAX && !m_currentRuleDataStack->isEmpty()) {
  8739. // This stuff is only executed when the style data retrieval is requested by client.
  8740. const unsigned start = m_propertyRange.start;
  8741. const unsigned end = m_propertyRange.end;
  8742. ASSERT(start < end);
  8743. String propertyString = String(m_dataStart.get() + start, end - start).stripWhiteSpace();
  8744. if (propertyString.endsWith(';'))
  8745. propertyString = propertyString.left(propertyString.length() - 1);
  8746. size_t colonIndex = propertyString.find(':');
  8747. ASSERT(colonIndex != notFound);
  8748. String name = propertyString.left(colonIndex).stripWhiteSpace();
  8749. String value = propertyString.substring(colonIndex + 1, propertyString.length()).stripWhiteSpace();
  8750. // The property range is relative to the declaration start offset.
  8751. SourceRange& topRuleBodyRange = m_currentRuleDataStack->last()->ruleBodyRange;
  8752. m_currentRuleDataStack->last()->styleSourceData->propertyData.append(
  8753. CSSPropertySourceData(name, value, isImportantFound, isPropertyParsed, SourceRange(start - topRuleBodyRange.start, end - topRuleBodyRange.start)));
  8754. }
  8755. resetPropertyRange();
  8756. }
  8757. static CSSPropertyID cssPropertyID(const UChar* propertyName, unsigned length)
  8758. {
  8759. if (!length)
  8760. return CSSPropertyInvalid;
  8761. if (length > maxCSSPropertyNameLength)
  8762. return CSSPropertyInvalid;
  8763. char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
  8764. for (unsigned i = 0; i != length; ++i) {
  8765. UChar c = propertyName[i];
  8766. if (c == 0 || c >= 0x7F)
  8767. return CSSPropertyInvalid; // illegal character
  8768. buffer[i] = toASCIILower(c);
  8769. }
  8770. buffer[length] = '\0';
  8771. const char* name = buffer;
  8772. if (buffer[0] == '-') {
  8773. #if ENABLE(LEGACY_CSS_VENDOR_PREFIXES)
  8774. // If the prefix is -apple- or -khtml-, change it to -webkit-.
  8775. // This makes the string one character longer.
  8776. if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
  8777. memmove(buffer + 7, buffer + 6, length + 1 - 6);
  8778. memcpy(buffer, "-webkit", 7);
  8779. ++length;
  8780. }
  8781. #endif
  8782. #if PLATFORM(IOS)
  8783. cssPropertyNameIOSAliasing(buffer, name, length);
  8784. #endif
  8785. }
  8786. const Property* hashTableEntry = findProperty(name, length);
  8787. return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
  8788. }
  8789. CSSPropertyID cssPropertyID(const String& string)
  8790. {
  8791. return cssPropertyID(string.characters(), string.length());
  8792. }
  8793. CSSPropertyID cssPropertyID(const CSSParserString& string)
  8794. {
  8795. return cssPropertyID(string.characters, string.length);
  8796. }
  8797. #if PLATFORM(IOS)
  8798. void cssPropertyNameIOSAliasing(const char* propertyName, const char*& propertyNameAlias, unsigned& newLength)
  8799. {
  8800. if (!strcmp(propertyName, "-webkit-hyphenate-locale")) {
  8801. // Worked in iOS 4.2.
  8802. static const char* const webkitLocale = "-webkit-locale";
  8803. propertyNameAlias = webkitLocale;
  8804. newLength = strlen(webkitLocale);
  8805. }
  8806. }
  8807. #endif
  8808. int cssValueKeywordID(const CSSParserString& string)
  8809. {
  8810. unsigned length = string.length;
  8811. if (!length)
  8812. return 0;
  8813. if (length > maxCSSValueKeywordLength)
  8814. return 0;
  8815. char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
  8816. for (unsigned i = 0; i != length; ++i) {
  8817. UChar c = string.characters[i];
  8818. if (c == 0 || c >= 0x7F)
  8819. return 0; // illegal character
  8820. buffer[i] = WTF::toASCIILower(c);
  8821. }
  8822. buffer[length] = '\0';
  8823. if (buffer[0] == '-') {
  8824. // If the prefix is -apple- or -khtml-, change it to -webkit-.
  8825. // This makes the string one character longer.
  8826. if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
  8827. memmove(buffer + 7, buffer + 6, length + 1 - 6);
  8828. memcpy(buffer, "-webkit", 7);
  8829. ++length;
  8830. }
  8831. }
  8832. const Value* hashTableEntry = findValue(buffer, length);
  8833. return hashTableEntry ? hashTableEntry->id : 0;
  8834. }
  8835. // "ident" from the CSS tokenizer, minus backslash-escape sequences
  8836. static bool isCSSTokenizerIdentifier(const String& string)
  8837. {
  8838. const UChar* p = string.characters();
  8839. const UChar* end = p + string.length();
  8840. // -?
  8841. if (p != end && p[0] == '-')
  8842. ++p;
  8843. // {nmstart}
  8844. if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p[0])))
  8845. return false;
  8846. ++p;
  8847. // {nmchar}*
  8848. for (; p != end; ++p) {
  8849. if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p[0])))
  8850. return false;
  8851. }
  8852. return true;
  8853. }
  8854. // "url" from the CSS tokenizer, minus backslash-escape sequences
  8855. static bool isCSSTokenizerURL(const String& string)
  8856. {
  8857. const UChar* p = string.characters();
  8858. const UChar* end = p + string.length();
  8859. for (; p != end; ++p) {
  8860. UChar c = p[0];
  8861. switch (c) {
  8862. case '!':
  8863. case '#':
  8864. case '$':
  8865. case '%':
  8866. case '&':
  8867. break;
  8868. default:
  8869. if (c < '*')
  8870. return false;
  8871. if (c <= '~')
  8872. break;
  8873. if (c < 128)
  8874. return false;
  8875. }
  8876. }
  8877. return true;
  8878. }
  8879. // We use single quotes for now because markup.cpp uses double quotes.
  8880. String quoteCSSString(const String& string)
  8881. {
  8882. // This function expands each character to at most 3 characters ('\u0010' -> '\' '1' '0') as well as adds
  8883. // 2 quote characters (before and after). Make sure the resulting size (3 * length + 2) will not overflow unsigned.
  8884. if (string.length() >= (std::numeric_limits<unsigned>::max() / 3) - 2)
  8885. return "";
  8886. // For efficiency, we first pre-calculate the length of the quoted string, then we build the actual one.
  8887. // Please see below for the actual logic.
  8888. unsigned quotedStringSize = 2; // Two quotes surrounding the entire string.
  8889. bool afterEscape = false;
  8890. for (unsigned i = 0; i < string.length(); ++i) {
  8891. UChar ch = string[i];
  8892. if (ch == '\\' || ch == '\'') {
  8893. quotedStringSize += 2;
  8894. afterEscape = false;
  8895. } else if (ch < 0x20 || ch == 0x7F) {
  8896. quotedStringSize += 2 + (ch >= 0x10);
  8897. afterEscape = true;
  8898. } else {
  8899. quotedStringSize += 1 + (afterEscape && (isASCIIHexDigit(ch) || ch == ' '));
  8900. afterEscape = false;
  8901. }
  8902. }
  8903. StringBuffer<UChar> buffer(quotedStringSize);
  8904. unsigned index = 0;
  8905. buffer[index++] = '\'';
  8906. afterEscape = false;
  8907. for (unsigned i = 0; i < string.length(); ++i) {
  8908. UChar ch = string[i];
  8909. if (ch == '\\' || ch == '\'') {
  8910. buffer[index++] = '\\';
  8911. buffer[index++] = ch;
  8912. afterEscape = false;
  8913. } else if (ch < 0x20 || ch == 0x7F) { // Control characters.
  8914. buffer[index++] = '\\';
  8915. placeByteAsHexCompressIfPossible(ch, buffer, index, Lowercase);
  8916. afterEscape = true;
  8917. } else {
  8918. // Space character may be required to separate backslash-escape sequence and normal characters.
  8919. if (afterEscape && (isASCIIHexDigit(ch) || ch == ' '))
  8920. buffer[index++] = ' ';
  8921. buffer[index++] = ch;
  8922. afterEscape = false;
  8923. }
  8924. }
  8925. buffer[index++] = '\'';
  8926. ASSERT(quotedStringSize == index);
  8927. return String::adopt(buffer);
  8928. }
  8929. String quoteCSSStringIfNeeded(const String& string)
  8930. {
  8931. return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string);
  8932. }
  8933. String quoteCSSURLIfNeeded(const String& string)
  8934. {
  8935. return isCSSTokenizerURL(string) ? string : quoteCSSString(string);
  8936. }
  8937. bool isValidNthToken(const CSSParserString& token)
  8938. {
  8939. // The tokenizer checks for the construct of an+b.
  8940. // However, since the {ident} rule precedes the {nth} rule, some of those
  8941. // tokens are identified as string literal. Furthermore we need to accept
  8942. // "odd" and "even" which does not match to an+b.
  8943. return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
  8944. || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");
  8945. }
  8946. }