diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/WebCore/css/CSSParser.cpp | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/WebCore/css/CSSParser.cpp')
-rw-r--r-- | Source/WebCore/css/CSSParser.cpp | 8007 |
1 files changed, 4630 insertions, 3377 deletions
diff --git a/Source/WebCore/css/CSSParser.cpp b/Source/WebCore/css/CSSParser.cpp index 54fd5e238..9aec1c8ac 100644 --- a/Source/WebCore/css/CSSParser.cpp +++ b/Source/WebCore/css/CSSParser.cpp @@ -1,12 +1,13 @@ /* * Copyright (C) 2003 Lars Knoll (knoll@kde.org) * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2004-2015 Apple Inc. All rights reserved. * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com> * Copyright (C) 2008 Eric Seidel <eric@webkit.org> * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. + * Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved. * Copyright (C) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2014 Google Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,88 +28,97 @@ #include "config.h" #include "CSSParser.h" +#include "CSSAnimationTriggerScrollValue.h" #include "CSSAspectRatioValue.h" #include "CSSBasicShapes.h" #include "CSSBorderImage.h" #include "CSSCanvasValue.h" +#include "CSSContentDistributionValue.h" #include "CSSCrossfadeValue.h" #include "CSSCursorImageValue.h" +#include "CSSCustomPropertyValue.h" +#include "CSSFilterImageValue.h" #include "CSSFontFaceRule.h" #include "CSSFontFaceSrcValue.h" +#include "CSSFontFeatureValue.h" +#include "CSSFontValue.h" #include "CSSFunctionValue.h" #include "CSSGradientValue.h" #include "CSSImageValue.h" #include "CSSInheritedValue.h" #include "CSSInitialValue.h" +#include "CSSKeyframeRule.h" +#include "CSSKeyframesRule.h" #include "CSSLineBoxContainValue.h" #include "CSSMediaRule.h" +#include "CSSNamedImageValue.h" #include "CSSPageRule.h" #include "CSSPrimitiveValue.h" +#include "CSSPrimitiveValueMappings.h" #include "CSSPropertySourceData.h" #include "CSSReflectValue.h" +#include "CSSRevertValue.h" #include "CSSSelector.h" +#include "CSSShadowValue.h" #include "CSSStyleSheet.h" #include "CSSTimingFunctionValue.h" #include "CSSUnicodeRangeValue.h" +#include "CSSUnsetValue.h" #include "CSSValueKeywords.h" #include "CSSValueList.h" #include "CSSValuePool.h" -#if ENABLE(CSS_VARIABLES) -#include "CSSVariableValue.h" -#endif +#include "CSSVariableDependentValue.h" #include "Counter.h" #include "Document.h" #include "FloatConversion.h" -#include "FontFeatureValue.h" -#include "FontValue.h" +#include "GridCoordinate.h" #include "HTMLParserIdioms.h" #include "HashTools.h" -#include "HistogramSupport.h" #include "MediaList.h" #include "MediaQueryExp.h" #include "Page.h" -#include "PageConsole.h" +#include "PageConsoleClient.h" #include "Pair.h" #include "Rect.h" #include "RenderTheme.h" #include "RuntimeEnabledFeatures.h" #include "SVGParserUtilities.h" +#include "SVGPathByteStream.h" +#include "SVGPathUtilities.h" +#include "SelectorChecker.h" +#include "SelectorCheckerTestFunctions.h" #include "Settings.h" -#include "ShadowValue.h" -#include "StylePropertySet.h" +#include "StyleProperties.h" #include "StylePropertyShorthand.h" #include "StyleRule.h" #include "StyleRuleImport.h" #include "StyleSheetContents.h" #include "TextEncoding.h" -#include "WebKitCSSKeyframeRule.h" -#include "WebKitCSSKeyframesRule.h" +#include "WebKitCSSFilterValue.h" #include "WebKitCSSRegionRule.h" #include "WebKitCSSTransformValue.h" +#include <JavaScriptCore/Profile.h> +#include <bitset> #include <limits.h> -#include <wtf/BitArray.h> #include <wtf/HexNumber.h> +#include <wtf/NeverDestroyed.h> +#include <wtf/StdLibExtras.h> #include <wtf/dtoa.h> #include <wtf/text/StringBuffer.h> #include <wtf/text/StringBuilder.h> #include <wtf/text/StringImpl.h> -#if ENABLE(CSS_IMAGE_SET) -#include "CSSImageSetValue.h" +#if ENABLE(CSS_GRID_LAYOUT) +#include "CSSGridLineNamesValue.h" +#include "CSSGridTemplateAreasValue.h" #endif -#if ENABLE(CSS_FILTERS) -#include "WebKitCSSFilterValue.h" -#if ENABLE(SVG) -#include "WebKitCSSSVGDocumentValue.h" -#endif +#if ENABLE(CSS_IMAGE_SET) +#include "CSSImageSetValue.h" #endif -#if ENABLE(CSS_SHADERS) -#include "WebKitCSSArrayFunctionValue.h" -#include "WebKitCSSMatFunctionValue.h" -#include "WebKitCSSMixFunctionValue.h" -#include "WebKitCSSShaderValue.h" +#if ENABLE(CSS_SCROLL_SNAP) +#include "LengthRepeat.h" #endif #if ENABLE(DASHBOARD_SUPPORT) @@ -123,7 +133,6 @@ extern int cssyydebug; extern int cssyyparse(WebCore::CSSParser*); -using namespace std; using namespace WTF; namespace { @@ -136,19 +145,19 @@ enum PropertyType { class ImplicitScope { WTF_MAKE_NONCOPYABLE(ImplicitScope); public: - ImplicitScope(WebCore::CSSParser* parser, PropertyType propertyType) + ImplicitScope(WebCore::CSSParser& parser, PropertyType propertyType) : m_parser(parser) { - m_parser->m_implicitShorthand = propertyType == PropertyImplicit; + m_parser.m_implicitShorthand = propertyType == PropertyImplicit; } ~ImplicitScope() { - m_parser->m_implicitShorthand = false; + m_parser.m_implicitShorthand = false; } private: - WebCore::CSSParser* m_parser; + WebCore::CSSParser& m_parser; }; } // namespace @@ -158,31 +167,10 @@ namespace WebCore { static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX; static const double MAX_SCALE = 1000000; -template <unsigned N> -static bool equal(const CSSParserString& a, const char (&b)[N]) +template<unsigned length> bool equalLettersIgnoringASCIICase(const CSSParserValue& value, const char (&lowercaseLetters)[length]) { - unsigned length = N - 1; // Ignore the trailing null character - if (a.length() != length) - return false; - - return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar*>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length); -} - -template <unsigned N> -static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N]) -{ - unsigned length = N - 1; // Ignore the trailing null character - if (a.length() != length) - return false; - - return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length); -} - -template <unsigned N> -static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N]) -{ - ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrimitiveValue::CSS_STRING); - return equalIgnoringCase(value->string, b); + ASSERT(value.unit == CSSPrimitiveValue::CSS_IDENT || value.unit == CSSPrimitiveValue::CSS_STRING); + return equalLettersIgnoringASCIICase(value.string, lowercaseLetters); } static bool hasPrefix(const char* string, unsigned length, const char* prefix) @@ -196,9 +184,10 @@ static bool hasPrefix(const char* string, unsigned length, const char* prefix) return false; } -static PassRefPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtr<CSSPrimitiveValue> first, PassRefPtr<CSSPrimitiveValue> second) +template<typename... Args> +static Ref<CSSPrimitiveValue> createPrimitiveValuePair(Args&&... args) { - return cssValuePool().createValue(Pair::create(first, second)); + return CSSValuePool::singleton().createValue(Pair::create(std::forward<Args>(args)...)); } class AnimationParseContext { @@ -248,45 +237,45 @@ private: const CSSParserContext& strictCSSParserContext() { - DEFINE_STATIC_LOCAL(CSSParserContext, strictContext, (CSSStrictMode)); + static NeverDestroyed<CSSParserContext> strictContext(CSSStrictMode); return strictContext; } -CSSParserContext::CSSParserContext(CSSParserMode mode, const KURL& baseURL) +CSSParserContext::CSSParserContext(CSSParserMode mode, const URL& baseURL) : baseURL(baseURL) , mode(mode) , isHTMLDocument(false) - , isCSSCustomFilterEnabled(false) - , isCSSStickyPositionEnabled(false) - , isCSSRegionsEnabled(false) - , isCSSCompositingEnabled(false) - , isCSSGridLayoutEnabled(false) -#if ENABLE(CSS_VARIABLES) - , isCSSVariablesEnabled(false) -#endif + , isCSSRegionsEnabled(RuntimeEnabledFeatures::sharedFeatures().cssRegionsEnabled()) + , isCSSCompositingEnabled(RuntimeEnabledFeatures::sharedFeatures().cssCompositingEnabled()) , needsSiteSpecificQuirks(false) , enforcesCSSMIMETypeInNoQuirksMode(true) , useLegacyBackgroundSizeShorthandBehavior(false) { +#if PLATFORM(IOS) + // FIXME: Force the site specific quirk below to work on iOS. Investigating other site specific quirks + // to see if we can enable the preference all together is to be handled by: + // <rdar://problem/8493309> Investigate Enabling Site Specific Quirks in MobileSafari and UIWebView + needsSiteSpecificQuirks = true; +#endif } -CSSParserContext::CSSParserContext(Document* document, const KURL& baseURL, const String& charset) - : baseURL(baseURL.isNull() ? document->baseURL() : baseURL) +CSSParserContext::CSSParserContext(Document& document, const URL& baseURL, const String& charset) + : baseURL(baseURL.isNull() ? document.baseURL() : baseURL) , charset(charset) - , mode(document->inQuirksMode() ? CSSQuirksMode : CSSStrictMode) - , isHTMLDocument(document->isHTMLDocument()) - , isCSSCustomFilterEnabled(document->settings() ? document->settings()->isCSSCustomFilterEnabled() : false) - , isCSSStickyPositionEnabled(document->cssStickyPositionEnabled()) - , isCSSRegionsEnabled(document->cssRegionsEnabled()) - , isCSSCompositingEnabled(document->cssCompositingEnabled()) - , isCSSGridLayoutEnabled(document->cssGridLayoutEnabled()) -#if ENABLE(CSS_VARIABLES) - , isCSSVariablesEnabled(document->settings() ? document->settings()->cssVariablesEnabled() : false) -#endif - , needsSiteSpecificQuirks(document->settings() ? document->settings()->needsSiteSpecificQuirks() : false) - , enforcesCSSMIMETypeInNoQuirksMode(!document->settings() || document->settings()->enforceCSSMIMETypeInNoQuirksMode()) - , useLegacyBackgroundSizeShorthandBehavior(document->settings() ? document->settings()->useLegacyBackgroundSizeShorthandBehavior() : false) + , mode(document.inQuirksMode() ? CSSQuirksMode : CSSStrictMode) + , isHTMLDocument(document.isHTMLDocument()) + , isCSSRegionsEnabled(document.cssRegionsEnabled()) + , isCSSCompositingEnabled(document.cssCompositingEnabled()) + , needsSiteSpecificQuirks(document.settings() ? document.settings()->needsSiteSpecificQuirks() : false) + , enforcesCSSMIMETypeInNoQuirksMode(!document.settings() || document.settings()->enforceCSSMIMETypeInNoQuirksMode()) + , useLegacyBackgroundSizeShorthandBehavior(document.settings() ? document.settings()->useLegacyBackgroundSizeShorthandBehavior() : false) { +#if PLATFORM(IOS) + // FIXME: Force the site specific quirk below to work on iOS. Investigating other site specific quirks + // to see if we can enable the preference all together is to be handled by: + // <rdar://problem/8493309> Investigate Enabling Site Specific Quirks in MobileSafari and UIWebView + needsSiteSpecificQuirks = true; +#endif } bool operator==(const CSSParserContext& a, const CSSParserContext& b) @@ -295,14 +284,8 @@ bool operator==(const CSSParserContext& a, const CSSParserContext& b) && a.charset == b.charset && a.mode == b.mode && a.isHTMLDocument == b.isHTMLDocument - && a.isCSSCustomFilterEnabled == b.isCSSCustomFilterEnabled - && a.isCSSStickyPositionEnabled == b.isCSSStickyPositionEnabled && a.isCSSRegionsEnabled == b.isCSSRegionsEnabled && a.isCSSCompositingEnabled == b.isCSSCompositingEnabled - && a.isCSSGridLayoutEnabled == b.isCSSGridLayoutEnabled -#if ENABLE(CSS_VARIABLES) - && a.isCSSVariablesEnabled == b.isCSSVariablesEnabled -#endif && a.needsSiteSpecificQuirks == b.needsSiteSpecificQuirks && a.enforcesCSSMIMETypeInNoQuirksMode == b.enforcesCSSMIMETypeInNoQuirksMode && a.useLegacyBackgroundSizeShorthandBehavior == b.useLegacyBackgroundSizeShorthandBehavior; @@ -312,35 +295,34 @@ CSSParser::CSSParser(const CSSParserContext& context) : m_context(context) , m_important(false) , m_id(CSSPropertyInvalid) - , m_styleSheet(0) -#if ENABLE(CSS3_CONDITIONAL_RULES) + , m_styleSheet(nullptr) , m_supportsCondition(false) -#endif - , m_selectorListForParseSelector(0) + , m_selectorListForParseSelector(nullptr) , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES) , m_inParseShorthand(0) , m_currentShorthand(CSSPropertyInvalid) , m_implicitShorthand(false) - , m_hasFontFaceOnlyValues(false) , m_hadSyntacticallyValidCSSRule(false) , m_logErrors(false) , m_ignoreErrorsInDeclaration(false) -#if ENABLE(CSS_SHADERS) - , m_inFilterRule(false) -#endif , m_defaultNamespace(starAtom) , m_parsedTextPrefixLength(0) + , m_nestedSelectorLevel(0) , m_propertyRange(UINT_MAX, UINT_MAX) - , m_ruleSourceDataResult(0) + , m_ruleSourceDataResult(nullptr) , m_parsingMode(NormalMode) , m_is8BitSource(false) - , m_currentCharacter8(0) - , m_currentCharacter16(0) + , m_currentCharacter8(nullptr) + , m_currentCharacter16(nullptr) , m_length(0) , m_token(0) , m_lineNumber(0) , m_tokenStartLineNumber(0) + , m_tokenStartColumnNumber(0) , m_lastSelectorLineNumber(0) + , m_columnOffsetForLine(0) + , m_sheetStartLineNumber(0) + , m_sheetStartColumnNumber(0) , m_allowImportRules(true) , m_allowNamespaceDeclarations(true) #if ENABLE(CSS_DEVICE_ADAPTATION) @@ -350,59 +332,29 @@ CSSParser::CSSParser(const CSSParserContext& context) #if YYDEBUG > 0 cssyydebug = 1; #endif - m_tokenStart.ptr8 = 0; + m_tokenStart.ptr8 = nullptr; } CSSParser::~CSSParser() { clearProperties(); - - deleteAllValues(m_floatingSelectors); - deleteAllValues(m_floatingSelectorVectors); - deleteAllValues(m_floatingValueLists); - deleteAllValues(m_floatingFunctions); } -template <typename CharacterType> -ALWAYS_INLINE static void makeLower(const CharacterType* input, CharacterType* output, unsigned length) +template<typename CharacterType> ALWAYS_INLINE static void convertToASCIILowercaseInPlace(CharacterType* characters, unsigned length) { - // FIXME: If we need Unicode lowercasing here, then we probably want the real kind - // that can potentially change the length of the string rather than the character - // by character kind. If we don't need Unicode lowercasing, it would be good to - // simplify this function. - - if (charactersAreAllASCII(input, length)) { - // Fast case for all-ASCII. - for (unsigned i = 0; i < length; i++) - output[i] = toASCIILower(input[i]); - } else { - for (unsigned i = 0; i < length; i++) - output[i] = Unicode::toLower(input[i]); - } -} - -void CSSParserString::lower() -{ - if (is8Bit()) { - makeLower(characters8(), characters8(), length()); - return; - } - - makeLower(characters16(), characters16(), length()); + for (unsigned i = 0; i < length; ++i) + characters[i] = toASCIILower(characters[i]); } -#if ENABLE(CSS_VARIABLES) -AtomicString CSSParserString::substring(unsigned position, unsigned length) const +void CSSParserString::convertToASCIILowercaseInPlace() { - ASSERT(m_length >= position + length); - if (is8Bit()) - return AtomicString(characters8() + position, length); - return AtomicString(characters16() + position, length); + WebCore::convertToASCIILowercaseInPlace(characters8(), length()); + else + WebCore::convertToASCIILowercaseInPlace(characters16(), length()); } -#endif -void CSSParser::setupParser(const char* prefix, unsigned prefixLength, const String& string, const char* suffix, unsigned suffixLength) +void CSSParser::setupParser(const char* prefix, unsigned prefixLength, StringView string, const char* suffix, unsigned suffixLength) { m_parsedTextPrefixLength = prefixLength; unsigned stringLength = string.length(); @@ -410,8 +362,8 @@ void CSSParser::setupParser(const char* prefix, unsigned prefixLength, const Str m_length = length; if (!stringLength || string.is8Bit()) { - m_dataStart8 = adoptArrayPtr(new LChar[length]); - for (unsigned i = 0; i < m_parsedTextPrefixLength; i++) + m_dataStart8 = std::make_unique<LChar[]>(length); + for (unsigned i = 0; i < m_parsedTextPrefixLength; ++i) m_dataStart8[i] = prefix[i]; if (stringLength) @@ -422,18 +374,18 @@ void CSSParser::setupParser(const char* prefix, unsigned prefixLength, const Str for (unsigned i = start; i < end; i++) m_dataStart8[i] = suffix[i - start]; - m_dataStart8[length - 1] = 0; + m_dataStart8[length - 1] = '\0'; m_is8BitSource = true; m_currentCharacter8 = m_dataStart8.get(); - m_currentCharacter16 = 0; + m_currentCharacter16 = nullptr; setTokenStart<LChar>(m_currentCharacter8); m_lexFunc = &CSSParser::realLex<LChar>; return; } - m_dataStart16 = adoptArrayPtr(new UChar[length]); - for (unsigned i = 0; i < m_parsedTextPrefixLength; i++) + m_dataStart16 = std::make_unique<UChar[]>(length); + for (unsigned i = 0; i < m_parsedTextPrefixLength; ++i) m_dataStart16[i] = prefix[i]; ASSERT(stringLength); @@ -444,62 +396,65 @@ void CSSParser::setupParser(const char* prefix, unsigned prefixLength, const Str for (unsigned i = start; i < end; i++) m_dataStart16[i] = suffix[i - start]; - m_dataStart16[length - 1] = 0; + m_dataStart16[length - 1] = '\0'; m_is8BitSource = false; - m_currentCharacter8 = 0; + m_currentCharacter8 = nullptr; m_currentCharacter16 = m_dataStart16.get(); setTokenStart<UChar>(m_currentCharacter16); m_lexFunc = &CSSParser::realLex<UChar>; } -void CSSParser::parseSheet(StyleSheetContents* sheet, const String& string, int startLineNumber, RuleSourceDataList* ruleSourceDataResult, bool logErrors) +void CSSParser::parseSheet(StyleSheetContents* sheet, const String& string, const TextPosition& textPosition, RuleSourceDataList* ruleSourceDataResult, bool logErrors) { setStyleSheet(sheet); m_defaultNamespace = starAtom; // Reset the default namespace. if (ruleSourceDataResult) - m_currentRuleDataStack = adoptPtr(new RuleSourceDataList()); + m_currentRuleDataStack = std::make_unique<RuleSourceDataList>(); m_ruleSourceDataResult = ruleSourceDataResult; m_logErrors = logErrors && sheet->singleOwnerDocument() && !sheet->baseURL().isEmpty() && sheet->singleOwnerDocument()->page(); m_ignoreErrorsInDeclaration = false; - m_lineNumber = startLineNumber; + m_sheetStartLineNumber = textPosition.m_line.zeroBasedInt(); + m_sheetStartColumnNumber = textPosition.m_column.zeroBasedInt(); + m_lineNumber = m_sheetStartLineNumber; + m_columnOffsetForLine = 0; setupParser("", string, ""); cssyyparse(this); sheet->shrinkToFit(); - m_currentRuleDataStack.clear(); - m_ruleSourceDataResult = 0; - m_rule = 0; + m_currentRuleDataStack.reset(); + m_ruleSourceDataResult = nullptr; + m_rule = nullptr; m_ignoreErrorsInDeclaration = false; m_logErrors = false; } -PassRefPtr<StyleRuleBase> CSSParser::parseRule(StyleSheetContents* sheet, const String& string) +RefPtr<StyleRuleBase> CSSParser::parseRule(StyleSheetContents* sheet, const String& string) { setStyleSheet(sheet); m_allowNamespaceDeclarations = false; setupParser("@-webkit-rule{", string, "} "); cssyyparse(this); - return m_rule.release(); + return m_rule; } -PassRefPtr<StyleKeyframe> CSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string) +RefPtr<StyleKeyframe> CSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string) { setStyleSheet(sheet); setupParser("@-webkit-keyframe-rule{ ", string, "} "); cssyyparse(this); - return m_keyframe.release(); + return m_keyframe; } -#if ENABLE(CSS3_CONDITIONAL_RULES) bool CSSParser::parseSupportsCondition(const String& string) { m_supportsCondition = false; - setupParser("@-webkit-supports-condition{ ", string, "} "); + // can't use { because tokenizer state switches from supports to initial state when it sees { token. + // instead insert one " " (which is WHITESPACE in CSSGrammar.y) + setupParser("@-webkit-supports-condition ", string, "} "); cssyyparse(this); return m_supportsCondition; } -#endif static inline bool isColorPropertyID(CSSPropertyID propertyId) { @@ -518,10 +473,8 @@ static inline bool isColorPropertyID(CSSPropertyID propertyId) case CSSPropertyWebkitBorderBeforeColor: case CSSPropertyWebkitBorderEndColor: case CSSPropertyWebkitBorderStartColor: - case CSSPropertyWebkitColumnRuleColor: -#if ENABLE(CSS3_TEXT) + case CSSPropertyColumnRuleColor: case CSSPropertyWebkitTextDecorationColor: -#endif // CSS3_TEXT case CSSPropertyWebkitTextEmphasisColor: case CSSPropertyWebkitTextFillColor: case CSSPropertyWebkitTextStrokeColor: @@ -531,36 +484,38 @@ static inline bool isColorPropertyID(CSSPropertyID propertyId) } } -static bool parseColorValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode) +bool CSSParser::isValidSystemColorValue(CSSValueID valueID) +{ + return valueID >= CSSValueAqua && valueID <= CSSValueAppleSystemYellow; +} + +static bool validPrimitiveValueColor(CSSValueID valueID, bool strict = false) +{ + return (valueID == CSSValueWebkitText || valueID == CSSValueCurrentcolor || valueID == CSSValueMenu + || CSSParser::isValidSystemColorValue(valueID) || valueID == CSSValueAlpha + || (valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText && !strict)); +} + +static CSSParser::ParseResult parseColorValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode) { ASSERT(!string.isEmpty()); bool strict = isStrictParserMode(cssParserMode); if (!isColorPropertyID(propertyId)) - return false; + return CSSParser::ParseResult::Error; + CSSParserString cssString; cssString.init(string); CSSValueID valueID = cssValueKeywordID(cssString); - bool validPrimitive = false; - if (valueID == CSSValueWebkitText) - validPrimitive = true; - else if (valueID == CSSValueCurrentcolor) - validPrimitive = true; - else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu - || (valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText && !strict)) { - validPrimitive = true; - } - - if (validPrimitive) { - RefPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID); - declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)); - return true; + if (validPrimitiveValueColor(valueID, strict)) { + RefPtr<CSSValue> value = CSSValuePool::singleton().createIdentifierValue(valueID); + return declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged; } RGBA32 color; if (!CSSParser::fastParseColor(color, string, strict && string[0] != '#')) - return false; - RefPtr<CSSValue> value = cssValuePool().createColorValue(color); - declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)); - return true; + return CSSParser::ParseResult::Error; + + RefPtr<CSSValue> value = CSSValuePool::singleton().createColorValue(color); + return declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged; } static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers) @@ -583,26 +538,36 @@ static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acce case CSSPropertyWebkitPaddingBefore: case CSSPropertyWebkitPaddingEnd: case CSSPropertyWebkitPaddingStart: +#if ENABLE(CSS_GRID_LAYOUT) + case CSSPropertyWebkitGridColumnGap: + case CSSPropertyWebkitGridRowGap: +#endif acceptsNegativeNumbers = false; return true; #if ENABLE(CSS_SHAPES) case CSSPropertyWebkitShapeMargin: - case CSSPropertyWebkitShapePadding: acceptsNegativeNumbers = false; - return RuntimeEnabledFeatures::cssShapesEnabled(); + return RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled(); #endif case CSSPropertyBottom: + case CSSPropertyCx: + case CSSPropertyCy: case CSSPropertyLeft: case CSSPropertyMarginBottom: case CSSPropertyMarginLeft: case CSSPropertyMarginRight: case CSSPropertyMarginTop: + case CSSPropertyR: + case CSSPropertyRx: + case CSSPropertyRy: case CSSPropertyRight: case CSSPropertyTop: case CSSPropertyWebkitMarginAfter: case CSSPropertyWebkitMarginBefore: case CSSPropertyWebkitMarginEnd: case CSSPropertyWebkitMarginStart: + case CSSPropertyX: + case CSSPropertyY: acceptsNegativeNumbers = true; return true; default: @@ -629,12 +594,12 @@ static inline bool parseSimpleLength(const CharacterType* characters, unsigned& return ok; } -static bool parseSimpleLengthValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode) +static CSSParser::ParseResult parseSimpleLengthValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode) { ASSERT(!string.isEmpty()); bool acceptsNegativeNumbers; if (!isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers)) - return false; + return CSSParser::ParseResult::Error; unsigned length = string.length(); double number; @@ -642,26 +607,27 @@ static bool parseSimpleLengthValue(MutableStylePropertySet* declaration, CSSProp if (string.is8Bit()) { if (!parseSimpleLength(string.characters8(), length, unit, number)) - return false; + return CSSParser::ParseResult::Error; } else { if (!parseSimpleLength(string.characters16(), length, unit, number)) - return false; + return CSSParser::ParseResult::Error; } if (unit == CSSPrimitiveValue::CSS_NUMBER) { if (number && isStrictParserMode(cssParserMode)) - return false; + return CSSParser::ParseResult::Error; unit = CSSPrimitiveValue::CSS_PX; } if (number < 0 && !acceptsNegativeNumbers) - return false; + return CSSParser::ParseResult::Error; + if (std::isinf(number)) + return CSSParser::ParseResult::Error; - RefPtr<CSSValue> value = cssValuePool().createValue(number, unit); - declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)); - return true; + RefPtr<CSSValue> value = CSSValuePool::singleton().createValue(number, unit); + return declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged; } -static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext) +static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext, StyleSheetContents* styleSheetContents) { if (!valueID) return false; @@ -679,7 +645,7 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int case CSSPropertyWebkitBorderBeforeStyle: case CSSPropertyWebkitBorderEndStyle: case CSSPropertyWebkitBorderStartStyle: - case CSSPropertyWebkitColumnRuleStyle: + case CSSPropertyColumnRuleStyle: if (valueID >= CSSValueNone && valueID <= CSSValueDouble) return true; break; @@ -700,14 +666,16 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int return true; break; case CSSPropertyDisplay: - // inline | block | list-item | run-in | inline-block | table | + // inline | block | list-item | inline-block | table | // inline-table | table-row-group | table-header-group | table-footer-group | table-row | // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none | inherit - // -webkit-flex | -webkit-inline-flex | -webkit-grid | -webkit-inline-grid + // flex | -webkit-flex | inline-flex | -webkit-inline-flex | -webkit-grid | -webkit-inline-grid if ((valueID >= CSSValueInline && valueID <= CSSValueWebkitInlineFlex) || valueID == CSSValueNone) return true; - if (parserContext.isCSSGridLayoutEnabled && (valueID == CSSValueWebkitGrid || valueID == CSSValueWebkitInlineGrid)) +#if ENABLE(CSS_GRID_LAYOUT) + if (valueID == CSSValueWebkitGrid || valueID == CSSValueWebkitInlineGrid) return true; +#endif break; case CSSPropertyEmptyCells: // show | hide | inherit @@ -722,9 +690,10 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int if (valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique) return true; break; - case CSSPropertyImageRendering: // auto | optimizeSpeed | optimizeQuality | -webkit-crisp-edges | -webkit-optimize-contrast + case CSSPropertyImageRendering: // auto | optimizeSpeed | optimizeQuality | -webkit-crisp-edges | -webkit-optimize-contrast | crisp-edges | pixelated + // optimizeSpeed and optimizeQuality are deprecated; a user agent must accept them as valid values but must treat them as having the same behavior as pixelated and auto respectively. if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizequality - || valueID == CSSValueWebkitCrispEdges || valueID == CSSValueWebkitOptimizeContrast) + || valueID == CSSValueWebkitCrispEdges || valueID == CSSValueWebkitOptimizeContrast || valueID == CSSValueCrispEdges || valueID == CSSValuePixelated) return true; break; case CSSPropertyListStylePosition: // inside | outside | inherit @@ -737,6 +706,10 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int if ((valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone) return true; break; + case CSSPropertyObjectFit: + if (valueID == CSSValueFill || valueID == CSSValueContain || valueID == CSSValueCover || valueID == CSSValueNone || valueID == CSSValueScaleDown) + return true; + break; case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit if (valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble)) return true; @@ -746,6 +719,18 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int if (valueID == CSSValueNormal || valueID == CSSValueBreakWord) return true; break; +#if ENABLE(TOUCH_EVENTS) + case CSSPropertyTouchAction: // auto | manipulation + if (valueID == CSSValueAuto || valueID == CSSValueManipulation) + return true; + break; +#endif +#if ENABLE(CSS_SCROLL_SNAP) + case CSSPropertyWebkitScrollSnapType: // none | mandatory | proximity + if (valueID == CSSValueNone || valueID == CSSValueMandatory || valueID == CSSValueProximity) + return true; + break; +#endif case CSSPropertyOverflowX: // visible | hidden | scroll | auto | marquee | overlay | inherit if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitMarquee) return true; @@ -773,11 +758,7 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int return true; break; case CSSPropertyPosition: // static | relative | absolute | fixed | sticky | inherit - if (valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed -#if ENABLE(CSS_STICKY_POSITION) - || (parserContext.isCSSStickyPositionEnabled && valueID == CSSValueWebkitSticky) -#endif - ) + if (valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed || valueID == CSSValueWebkitSticky) return true; break; case CSSPropertyResize: // none | both | horizontal | vertical | auto @@ -821,7 +802,7 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int return true; break; case CSSPropertyWebkitAppearance: - if ((valueID >= CSSValueCheckbox && valueID <= CSSValueTextarea) || valueID == CSSValueNone) + if ((valueID >= CSSValueCheckbox && valueID <= CSSValueCapsLockIndicator) || valueID == CSSValueNone) return true; break; case CSSPropertyWebkitBackfaceVisibility: @@ -829,12 +810,15 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int return true; break; #if ENABLE(CSS_COMPOSITING) - case CSSPropertyWebkitBlendMode: + case CSSPropertyMixBlendMode: if (parserContext.isCSSCompositingEnabled && (valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen || valueID == CSSValueOverlay || valueID == CSSValueDarken || valueID == CSSValueLighten || valueID == CSSValueColorDodge || valueID == CSSValueColorBurn || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference - || valueID == CSSValueExclusion || valueID == CSSValueHue || valueID == CSSValueSaturation || valueID == CSSValueColor - || valueID == CSSValueLuminosity)) + || valueID == CSSValueExclusion || valueID == CSSValuePlusDarker || valueID == CSSValuePlusLighter)) + return true; + break; + case CSSPropertyIsolation: + if (parserContext.isCSSCompositingEnabled && (valueID == CSSValueAuto || valueID == CSSValueIsolate)) return true; break; #endif @@ -868,34 +852,18 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int if (valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify) return true; break; - case CSSPropertyWebkitColorCorrection: - if (valueID == CSSValueSrgb || valueID == CSSValueDefault) + case CSSPropertyColumnFill: + if (valueID == CSSValueAuto || valueID == CSSValueBalance) return true; break; - case CSSPropertyWebkitAlignContent: - if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch) - return true; - break; - case CSSPropertyWebkitAlignItems: - if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch) - return true; - break; - case CSSPropertyWebkitAlignSelf: - if (valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch) - return true; - break; - case CSSPropertyWebkitFlexDirection: + case CSSPropertyFlexDirection: if (valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse) return true; break; - case CSSPropertyWebkitFlexWrap: + case CSSPropertyFlexWrap: if (valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse) return true; break; - case CSSPropertyWebkitJustifyContent: - if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround) - return true; - break; case CSSPropertyWebkitFontKerning: if (valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone) return true; @@ -908,10 +876,6 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int if (valueID == CSSValueNone || valueID == CSSValueManual || valueID == CSSValueAuto) return true; break; - case CSSPropertyWebkitGridAutoFlow: - if (valueID == CSSValueNone || valueID == CSSValueRow || valueID == CSSValueColumn) - return true; - break; case CSSPropertyWebkitLineAlign: if (valueID == CSSValueNone || valueID == CSSValueEdges) return true; @@ -975,7 +939,7 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int break; case CSSPropertyWebkitRubyPosition: - if (valueID == CSSValueBefore || valueID == CSSValueAfter) + if (valueID == CSSValueBefore || valueID == CSSValueAfter || valueID == CSSValueInterCharacter) return true; break; @@ -990,14 +954,10 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int if (valueID == CSSValueNone || valueID == CSSValueHorizontal) return true; break; - case CSSPropertyWebkitTextEmphasisPosition: - if (valueID == CSSValueOver || valueID == CSSValueUnder) - return true; - break; #if ENABLE(CSS3_TEXT) case CSSPropertyWebkitTextJustify: - // auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida - if ((valueID >= CSSValueInterWord && valueID <= CSSValueKashida) || valueID == CSSValueAuto || valueID == CSSValueNone) + // auto | none | inter-word | distribute + if (valueID == CSSValueInterWord || valueID == CSSValueDistribute || valueID == CSSValueAuto || valueID == CSSValueNone) return true; break; #endif // CSS3_TEXT @@ -1006,6 +966,13 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int if (valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone) return true; break; +#if ENABLE(IOS_TEXT_AUTOSIZING) + case CSSPropertyWebkitTextSizeAdjust: + if (valueID == CSSValueAuto || valueID == CSSValueNone) + return true; + break; +#endif + case CSSPropertyTransformStyle: case CSSPropertyWebkitTransformStyle: if (valueID == CSSValueFlat || valueID == CSSValuePreserve3d) return true; @@ -1015,27 +982,21 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int return true; break; case CSSPropertyWebkitUserModify: // read-only | read-write - if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly) + if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly) { + if (styleSheetContents) + styleSheetContents->parserSetUsesStyleBasedEditability(); return true; + } break; case CSSPropertyWebkitUserSelect: // auto | none | text | all - if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll) - return true; - break; -#if ENABLE(CSS_EXCLUSIONS) - case CSSPropertyWebkitWrapFlow: - if (!RuntimeEnabledFeatures::cssExclusionsEnabled()) - return false; - if (valueID == CSSValueAuto || valueID == CSSValueBoth || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueMaximum || valueID == CSSValueClear) + if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText) return true; - break; - case CSSPropertyWebkitWrapThrough: - if (!RuntimeEnabledFeatures::cssExclusionsEnabled()) - return false; - if (valueID == CSSValueWrap || valueID == CSSValueNone) + if (valueID == CSSValueAll) { + if (styleSheetContents) + styleSheetContents->parserSetUsesStyleBasedEditability(); return true; + } break; -#endif case CSSPropertyWebkitWritingMode: if (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt) return true; @@ -1044,14 +1005,49 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int if (valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap) return true; break; - case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension) - if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord) + case CSSPropertyWordBreak: // normal | break-all | keep-all | break-word (this is a custom extension) + if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueKeepAll || valueID == CSSValueBreakWord) + return true; + break; +#if ENABLE(CSS_TRAILING_WORD) + case CSSPropertyAppleTrailingWord: // auto | -apple-partially-balanced + if (valueID == CSSValueAuto || valueID == CSSValueWebkitPartiallyBalanced) + return true; + break; +#endif + case CSSPropertyFontVariantPosition: // normal | sub | super + if (valueID == CSSValueNormal || valueID == CSSValueSub || valueID == CSSValueSuper) + return true; + break; + case CSSPropertyFontVariantCaps: // normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps + if (valueID == CSSValueNormal || valueID == CSSValueSmallCaps || valueID == CSSValueAllSmallCaps || valueID == CSSValuePetiteCaps || valueID == CSSValueAllPetiteCaps || valueID == CSSValueUnicase || valueID == CSSValueTitlingCaps) + return true; + break; + case CSSPropertyFontVariantAlternates: // We only support the normal and historical-forms values. + if (valueID == CSSValueNormal || valueID == CSSValueHistoricalForms) + return true; + break; + + case CSSPropertyBreakAfter: + case CSSPropertyBreakBefore: + // auto | avoid | left | right | recto | verso | column | page | region | avoid-page | avoid-column | avoid-region + if (valueID == CSSValueAuto || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight + || valueID == CSSValueRecto || valueID == CSSValueVerso || valueID == CSSValueColumn || valueID == CSSValuePage + || valueID == CSSValueRegion || valueID == CSSValueAvoidColumn || valueID == CSSValueAvoidPage || valueID == CSSValueAvoidRegion) + return true; + break; + case CSSPropertyBreakInside: + // auto | avoid | avoid-page | avoid-column | avoid-region + if (valueID == CSSValueAuto || valueID == CSSValueAvoid || valueID == CSSValueAvoidColumn || valueID == CSSValueAvoidPage || valueID == CSSValueAvoidRegion) return true; break; default: ASSERT_NOT_REACHED(); return false; } +#if !ENABLE(CSS_COMPOSITING) && !ENABLE(CSS_REGIONS) + UNUSED_PARAM(parserContext); +#endif return false; } @@ -1064,6 +1060,9 @@ static inline bool isKeywordPropertyID(CSSPropertyID propertyId) case CSSPropertyBorderRightStyle: case CSSPropertyBorderTopStyle: case CSSPropertyBoxSizing: + case CSSPropertyBreakAfter: + case CSSPropertyBreakBefore: + case CSSPropertyBreakInside: case CSSPropertyCaptionSide: case CSSPropertyClear: case CSSPropertyDirection: @@ -1074,6 +1073,7 @@ static inline bool isKeywordPropertyID(CSSPropertyID propertyId) case CSSPropertyImageRendering: case CSSPropertyListStylePosition: case CSSPropertyListStyleType: + case CSSPropertyObjectFit: case CSSPropertyOutlineStyle: case CSSPropertyOverflowWrap: case CSSPropertyOverflowX: @@ -1098,7 +1098,8 @@ static inline bool isKeywordPropertyID(CSSPropertyID propertyId) case CSSPropertyVisibility: case CSSPropertyWebkitAppearance: #if ENABLE(CSS_COMPOSITING) - case CSSPropertyWebkitBlendMode: + case CSSPropertyMixBlendMode: + case CSSPropertyIsolation: #endif case CSSPropertyWebkitBackfaceVisibility: case CSSPropertyWebkitBorderAfterStyle: @@ -1114,21 +1115,16 @@ static inline bool isKeywordPropertyID(CSSPropertyID propertyId) case CSSPropertyWebkitBoxLines: case CSSPropertyWebkitBoxOrient: case CSSPropertyWebkitBoxPack: - case CSSPropertyWebkitColorCorrection: case CSSPropertyWebkitColumnBreakAfter: case CSSPropertyWebkitColumnBreakBefore: case CSSPropertyWebkitColumnBreakInside: - case CSSPropertyWebkitColumnRuleStyle: - case CSSPropertyWebkitAlignContent: - case CSSPropertyWebkitAlignItems: - case CSSPropertyWebkitAlignSelf: - case CSSPropertyWebkitFlexDirection: - case CSSPropertyWebkitFlexWrap: - case CSSPropertyWebkitJustifyContent: + case CSSPropertyColumnFill: + case CSSPropertyColumnRuleStyle: + case CSSPropertyFlexDirection: + case CSSPropertyFlexWrap: case CSSPropertyWebkitFontKerning: case CSSPropertyWebkitFontSmoothing: case CSSPropertyWebkitHyphens: - case CSSPropertyWebkitGridAutoFlow: case CSSPropertyWebkitLineAlign: case CSSPropertyWebkitLineBreak: case CSSPropertyWebkitLineSnap: @@ -1155,42 +1151,57 @@ static inline bool isKeywordPropertyID(CSSPropertyID propertyId) case CSSPropertyWebkitTextAlignLast: #endif // CSS3_TEXT case CSSPropertyWebkitTextCombine: - case CSSPropertyWebkitTextEmphasisPosition: #if ENABLE(CSS3_TEXT) case CSSPropertyWebkitTextJustify: #endif // CSS3_TEXT case CSSPropertyWebkitTextSecurity: + case CSSPropertyTransformStyle: case CSSPropertyWebkitTransformStyle: case CSSPropertyWebkitUserDrag: case CSSPropertyWebkitUserModify: case CSSPropertyWebkitUserSelect: -#if ENABLE(CSS_EXCLUSIONS) - case CSSPropertyWebkitWrapFlow: - case CSSPropertyWebkitWrapThrough: -#endif case CSSPropertyWebkitWritingMode: case CSSPropertyWhiteSpace: case CSSPropertyWordBreak: case CSSPropertyWordWrap: +#if ENABLE(TOUCH_EVENTS) + case CSSPropertyTouchAction: +#endif +#if ENABLE(CSS_SCROLL_SNAP) + case CSSPropertyWebkitScrollSnapType: +#endif +#if ENABLE(CSS_TRAILING_WORD) + case CSSPropertyAppleTrailingWord: +#endif + case CSSPropertyFontVariantPosition: + case CSSPropertyFontVariantCaps: + case CSSPropertyFontVariantAlternates: return true; default: return false; } } -static bool parseKeywordValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext) +static bool isUniversalKeyword(const String& string) +{ + // These keywords can be used for all properties. + return equalLettersIgnoringASCIICase(string, "initial") + || equalLettersIgnoringASCIICase(string, "inherit") + || equalLettersIgnoringASCIICase(string, "unset") + || equalLettersIgnoringASCIICase(string, "revert"); +} + +static CSSParser::ParseResult parseKeywordValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext, StyleSheetContents* styleSheetContents) { ASSERT(!string.isEmpty()); if (!isKeywordPropertyID(propertyId)) { - // All properties accept the values of "initial" and "inherit". - String lowerCaseString = string.lower(); - if (lowerCaseString != "initial" && lowerCaseString != "inherit") - return false; + if (!isUniversalKeyword(string)) + return CSSParser::ParseResult::Error; - // Parse initial/inherit shorthands using the CSSParser. + // Don't try to parse initial/inherit/unset/revert shorthands; return an error so the caller will use the full CSS parser. if (shorthandForProperty(propertyId).length()) - return false; + return CSSParser::ParseResult::Error; } CSSParserString cssString; @@ -1198,25 +1209,29 @@ static bool parseKeywordValue(MutableStylePropertySet* declaration, CSSPropertyI CSSValueID valueID = cssValueKeywordID(cssString); if (!valueID) - return false; + return CSSParser::ParseResult::Error; RefPtr<CSSValue> value; if (valueID == CSSValueInherit) - value = cssValuePool().createInheritedValue(); + value = CSSValuePool::singleton().createInheritedValue(); else if (valueID == CSSValueInitial) - value = cssValuePool().createExplicitInitialValue(); - else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext)) - value = cssValuePool().createIdentifierValue(valueID); + value = CSSValuePool::singleton().createExplicitInitialValue(); + else if (valueID == CSSValueUnset) + value = CSSValuePool::singleton().createUnsetValue(); + else if (valueID == CSSValueRevert) + value = CSSValuePool::singleton().createRevertValue(); + else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext, styleSheetContents)) + value = CSSValuePool::singleton().createIdentifierValue(valueID); else - return false; + return CSSParser::ParseResult::Error; - declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)); - return true; + return declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged; } template <typename CharacterType> -static bool parseTransformArguments(WebKitCSSTransformValue* transformValue, CharacterType* characters, unsigned length, unsigned start, unsigned expectedCount) +static bool parseTransformTranslateArguments(WebKitCSSTransformValue& transformValue, CharacterType* characters, unsigned length, unsigned start, unsigned expectedCount) { + auto& cssValuePool = CSSValuePool::singleton(); while (expectedCount) { size_t end = WTF::find(characters, length, expectedCount == 1 ? ')' : ',', start); if (end == notFound || (expectedCount == 1 && end != length - 1)) @@ -1228,23 +1243,26 @@ static bool parseTransformArguments(WebKitCSSTransformValue* transformValue, Cha return false; if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER)) return false; - transformValue->append(cssValuePool().createValue(number, unit)); + transformValue.append(cssValuePool.createValue(number, CSSPrimitiveValue::CSS_PX)); start = end + 1; --expectedCount; } return true; } -static bool parseTranslateTransformValue(MutableStylePropertySet* properties, CSSPropertyID propertyID, const String& string, bool important) +static CSSParser::ParseResult parseTranslateTransformValue(MutableStyleProperties* properties, CSSPropertyID propertyID, const String& string, bool important) { - if (propertyID != CSSPropertyWebkitTransform) - return false; + if (propertyID != CSSPropertyTransform) + return CSSParser::ParseResult::Error; + static const unsigned shortestValidTransformStringLength = 12; static const unsigned likelyMultipartTransformStringLengthCutoff = 32; if (string.length() < shortestValidTransformStringLength || string.length() > likelyMultipartTransformStringLengthCutoff) - return false; + return CSSParser::ParseResult::Error; + if (!string.startsWith("translate", false)) - return false; + return CSSParser::ParseResult::Error; + UChar c9 = toASCIILower(string[9]); UChar c10 = toASCIILower(string[10]); @@ -1266,62 +1284,63 @@ static bool parseTranslateTransformValue(MutableStylePropertySet* properties, CS expectedArgumentCount = 3; argumentStart = 12; } else - return false; + return CSSParser::ParseResult::Error; RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(transformType); bool success; if (string.is8Bit()) - success = parseTransformArguments(transformValue.get(), string.characters8(), string.length(), argumentStart, expectedArgumentCount); + success = parseTransformTranslateArguments(*transformValue, string.characters8(), string.length(), argumentStart, expectedArgumentCount); else - success = parseTransformArguments(transformValue.get(), string.characters16(), string.length(), argumentStart, expectedArgumentCount); + success = parseTransformTranslateArguments(*transformValue, string.characters16(), string.length(), argumentStart, expectedArgumentCount); if (!success) - return false; + return CSSParser::ParseResult::Error; + RefPtr<CSSValueList> result = CSSValueList::createSpaceSeparated(); - result->append(transformValue.release()); - properties->addParsedProperty(CSSProperty(CSSPropertyWebkitTransform, result.release(), important)); - return true; + result->append(transformValue.releaseNonNull()); + return properties->addParsedProperty(CSSProperty(CSSPropertyTransform, result.release(), important)) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged; } -PassRefPtr<CSSValueList> CSSParser::parseFontFaceValue(const AtomicString& string) +RefPtr<CSSValueList> CSSParser::parseFontFaceValue(const AtomicString& string) { if (string.isEmpty()) - return 0; - RefPtr<MutableStylePropertySet> dummyStyle = MutableStylePropertySet::create(); - if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, CSSQuirksMode, 0)) - return 0; + return nullptr; - RefPtr<CSSValue> fontFamily = dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily); - if (!fontFamily->isValueList()) - return 0; // FIXME: "initial" and "inherit" should be parsed as font names in the face attribute. - return static_pointer_cast<CSSValueList>(fontFamily.release()); -} + Ref<CSSValueList> valueList = CSSValueList::createCommaSeparated(); -#if ENABLE(CSS_VARIABLES) -bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, Document* document) -{ - ASSERT(!string.isEmpty()); + Vector<String> familyNames; + string.string().split(',', true, familyNames); - CSSParserContext context(document); + auto& cssValuePool = CSSValuePool::singleton(); + for (auto& familyName : familyNames) { + String stripped = stripLeadingAndTrailingHTMLSpaces(familyName); + if (stripped.isEmpty()) + return nullptr; - if (parseSimpleLengthValue(declaration, propertyID, string, important, context.mode)) - return true; - if (parseColorValue(declaration, propertyID, string, important, context.mode)) - return true; - if (parseKeywordValue(declaration, propertyID, string, important, context)) - return true; + RefPtr<CSSValue> value; + for (auto propertyID : { CSSValueSerif, CSSValueSansSerif, CSSValueCursive, CSSValueFantasy, CSSValueMonospace, CSSValueWebkitBody }) { + if (equalIgnoringASCIICase(stripped, getValueName(propertyID))) { + value = cssValuePool.createIdentifierValue(propertyID); + break; + } + } + if (!value) + value = cssValuePool.createFontFamilyValue(stripped); + valueList->append(value.releaseNonNull()); + } - CSSParser parser(context); - return parser.parseValue(declaration, propertyID, string, important, static_cast<StyleSheetContents*>(0)); + return WTFMove(valueList); } -#endif -bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet) +CSSParser::ParseResult CSSParser::parseValue(MutableStyleProperties* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet) { ASSERT(!string.isEmpty()); - if (parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode)) - return true; - if (parseColorValue(declaration, propertyID, string, important, cssParserMode)) - return true; + CSSParser::ParseResult result = parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode); + if (result != ParseResult::Error) + return result; + + result = parseColorValue(declaration, propertyID, string, important, cssParserMode); + if (result != ParseResult::Error) + return result; CSSParserContext context(cssParserMode); if (contextStyleSheet) { @@ -1329,16 +1348,32 @@ bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID p context.mode = cssParserMode; } - if (parseKeywordValue(declaration, propertyID, string, important, context)) - return true; - if (parseTranslateTransformValue(declaration, propertyID, string, important)) - return true; + result = parseKeywordValue(declaration, propertyID, string, important, context, contextStyleSheet); + if (result != ParseResult::Error) + return result; + + result = parseTranslateTransformValue(declaration, propertyID, string, important); + if (result != ParseResult::Error) + return result; CSSParser parser(context); return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet); } -bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet) +CSSParser::ParseResult CSSParser::parseCustomPropertyValue(MutableStyleProperties* declaration, const AtomicString& propertyName, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet) +{ + CSSParserContext context(cssParserMode); + if (contextStyleSheet) { + context = contextStyleSheet->parserContext(); + context.mode = cssParserMode; + } + + CSSParser parser(context); + parser.setCustomPropertyName(propertyName); + return parser.parseValue(declaration, CSSPropertyCustom, string, important, contextStyleSheet); +} + +CSSParser::ParseResult CSSParser::parseValue(MutableStyleProperties* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet) { setStyleSheet(contextStyleSheet); @@ -1349,24 +1384,25 @@ bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID p cssyyparse(this); - m_rule = 0; + m_rule = nullptr; + + ParseResult result = ParseResult::Error; - bool ok = false; - if (m_hasFontFaceOnlyValues) - deleteFontFaceOnlyValues(); if (!m_parsedProperties.isEmpty()) { - ok = true; - declaration->addParsedProperties(m_parsedProperties); + result = declaration->addParsedProperties(m_parsedProperties) ? ParseResult::Changed : ParseResult::Unchanged; clearProperties(); } - return ok; + return result; } // The color will only be changed when string contains a valid CSS color, so callers // can set it to a default color and ignore the boolean result. bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict) { + if (string.isEmpty()) + return false; + // First try creating a color specified by name, rgba(), rgb() or "#" syntax. if (fastParseColor(color, string, strict)) return true; @@ -1377,15 +1413,15 @@ bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict) if (!parser.parseColor(string)) return false; - CSSValue* value = parser.m_parsedProperties.first().value(); - if (!value->isPrimitiveValue()) + CSSValue& value = *parser.m_parsedProperties.first().value(); + if (!is<CSSPrimitiveValue>(value)) return false; - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - if (!primitiveValue->isRGBColor()) + CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(value); + if (!primitiveValue.isRGBColor()) return false; - color = primitiveValue->getRGBA32Value(); + color = primitiveValue.getRGBA32Value(); return true; } @@ -1393,7 +1429,7 @@ bool CSSParser::parseColor(const String& string) { setupParser("@-webkit-decls{color:", string, "} "); cssyyparse(this); - m_rule = 0; + m_rule = nullptr; return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor; } @@ -1406,10 +1442,14 @@ bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* CSSParserString cssColor; cssColor.init(string); CSSValueID id = cssValueKeywordID(cssColor); - if (id <= 0) + if (!validPrimitiveValueColor(id)) + return false; + + Color parsedColor = document->page()->theme().systemColor(id); + if (!parsedColor.isValid()) return false; - color = document->page()->theme()->systemColor(id).rgb(); + color = parsedColor.rgb(); return true; } @@ -1421,34 +1461,31 @@ void CSSParser::parseSelector(const String& string, CSSSelectorList& selectorLis cssyyparse(this); - m_selectorListForParseSelector = 0; + m_selectorListForParseSelector = nullptr; } -PassRefPtr<ImmutableStylePropertySet> CSSParser::parseInlineStyleDeclaration(const String& string, Element* element) +Ref<ImmutableStyleProperties> CSSParser::parseInlineStyleDeclaration(const String& string, Element* element) { - CSSParserContext context = element->document()->elementSheet()->contents()->parserContext(); - context.mode = strictToCSSParserMode(element->isHTMLElement() && !element->document()->inQuirksMode()); - return CSSParser(context).parseDeclaration(string, element->document()->elementSheet()->contents()); + CSSParserContext context = element->document().elementSheet().contents().parserContext(); + context.mode = strictToCSSParserMode(element->isHTMLElement() && !element->document().inQuirksMode()); + return CSSParser(context).parseDeclaration(string, &element->document().elementSheet().contents()); } -PassRefPtr<ImmutableStylePropertySet> CSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet) +Ref<ImmutableStyleProperties> CSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet) { setStyleSheet(contextStyleSheet); setupParser("@-webkit-decls{", string, "} "); cssyyparse(this); - m_rule = 0; + m_rule = nullptr; - if (m_hasFontFaceOnlyValues) - deleteFontFaceOnlyValues(); - - RefPtr<ImmutableStylePropertySet> style = createStylePropertySet(); + Ref<ImmutableStyleProperties> style = createStyleProperties(); clearProperties(); - return style.release(); + return style; } -bool CSSParser::parseDeclaration(MutableStylePropertySet* declaration, const String& string, PassRefPtr<CSSRuleSourceData> prpRuleSourceData, StyleSheetContents* contextStyleSheet) +bool CSSParser::parseDeclaration(MutableStyleProperties* declaration, const String& string, PassRefPtr<CSSRuleSourceData> prpRuleSourceData, StyleSheetContents* contextStyleSheet) { // Length of the "@-webkit-decls{" prefix. static const unsigned prefixLength = 15; @@ -1457,17 +1494,15 @@ bool CSSParser::parseDeclaration(MutableStylePropertySet* declaration, const Str RefPtr<CSSRuleSourceData> ruleSourceData = prpRuleSourceData; if (ruleSourceData) { - m_currentRuleDataStack = adoptPtr(new RuleSourceDataList()); + m_currentRuleDataStack = std::make_unique<RuleSourceDataList>(); m_currentRuleDataStack->append(ruleSourceData); } setupParser("@-webkit-decls{", string, "} "); cssyyparse(this); - m_rule = 0; + m_rule = nullptr; bool ok = false; - if (m_hasFontFaceOnlyValues) - deleteFontFaceOnlyValues(); if (!m_parsedProperties.isEmpty()) { ok = true; declaration->addParsedProperties(m_parsedProperties); @@ -1485,13 +1520,13 @@ bool CSSParser::parseDeclaration(MutableStylePropertySet* declaration, const Str } fixUnparsedPropertyRanges(ruleSourceData.get()); - m_currentRuleDataStack.clear(); + m_currentRuleDataStack.reset(); } return ok; } -PassOwnPtr<MediaQuery> CSSParser::parseMediaQuery(const String& string) +std::unique_ptr<MediaQuery> CSSParser::parseMediaQuery(const String& string) { if (string.isEmpty()) return nullptr; @@ -1503,57 +1538,101 @@ PassOwnPtr<MediaQuery> CSSParser::parseMediaQuery(const String& string) setupParser("@-webkit-mediaquery ", string, "} "); cssyyparse(this); - return m_mediaQuery.release(); + return WTFMove(m_mediaQuery); } -#if ENABLE(CSS_VARIABLES) -static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties, HashSet<AtomicString>& seenVariables) -#else -static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties) -#endif +Vector<CSSParser::SourceSize> CSSParser::parseSizesAttribute(StringView string) +{ + Vector<SourceSize> result; + + if (string.isEmpty()) + return result; + + ASSERT(!m_sourceSizeList); + + setupParser("@-webkit-sizesattr ", string, "}"); + cssyyparse(this); + + if (!m_sourceSizeList) + return result; + + result = WTFMove(*m_sourceSizeList); + m_sourceSizeList = nullptr; + return result; +} + +// FIXME(141289): The following two constructors are only needed because of a bug in MSVC 2013 (and prior). +// We should remove this code as soon as a Visual Studio update that fixes this problem is released. +CSSParser::SourceSize::SourceSize(CSSParser::SourceSize&& original) + : expression(WTFMove(original.expression)) + , length(original.length) +{ +} + +CSSParser::SourceSize::SourceSize(std::unique_ptr<MediaQueryExp>&& origExp, RefPtr<CSSValue> value) + : expression(WTFMove(origExp)) + , length(value) +{ +} + +CSSParser::SourceSize CSSParser::sourceSize(std::unique_ptr<MediaQueryExp>&& expression, CSSParserValue& parserValue) +{ + RefPtr<CSSValue> value; + if (isCalculation(parserValue)) { + auto* args = parserValue.function->args.get(); + if (args && args->size()) + value = CSSCalcValue::create(parserValue.function->name, *args, CalculationRangeNonNegative); + } + if (!value) + value = parserValue.createCSSValue(); + destroy(parserValue); + // FIXME: Calling the constructor explicitly here to work around an MSVC bug. + // For other compilers, we did not need to define the constructors and we could use aggregate initialization syntax. + return SourceSize(WTFMove(expression), WTFMove(value)); +} + +static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, std::bitset<numCSSProperties>& seenProperties, HashSet<AtomicString>& seenCustomProperties) { // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found. for (int i = input.size() - 1; i >= 0; --i) { const CSSProperty& property = input[i]; if (property.isImportant() != important) continue; -#if ENABLE(CSS_VARIABLES) - if (property.id() == CSSPropertyVariable) { - const AtomicString& name = static_cast<CSSVariableValue*>(property.value())->name(); - if (seenVariables.contains(name)) - continue; - seenVariables.add(name); - output[--unusedEntries] = property; + + if (property.id() == CSSPropertyCustom) { + if (property.value()) { + const AtomicString& name = downcast<CSSCustomPropertyValue>(*property.value()).name(); + if (seenCustomProperties.contains(name)) + continue; + seenCustomProperties.add(name); + output[--unusedEntries] = property; + } continue; } -#endif + const unsigned propertyIDIndex = property.id() - firstCSSProperty; - if (seenProperties.get(propertyIDIndex)) + ASSERT(propertyIDIndex < seenProperties.size()); + if (seenProperties[propertyIDIndex]) continue; seenProperties.set(propertyIDIndex); output[--unusedEntries] = property; } } -PassRefPtr<ImmutableStylePropertySet> CSSParser::createStylePropertySet() +Ref<ImmutableStyleProperties> CSSParser::createStyleProperties() { - BitArray<numCSSProperties> seenProperties; + std::bitset<numCSSProperties> seenProperties; size_t unusedEntries = m_parsedProperties.size(); Vector<CSSProperty, 256> results(unusedEntries); // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found. -#if ENABLE(CSS_VARIABLES) - HashSet<AtomicString> seenVariables; - filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables); - filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables); -#else - filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties); - filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties); -#endif + HashSet<AtomicString> seenCustomProperties; + filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties, seenCustomProperties); + filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties, seenCustomProperties); if (unusedEntries) results.remove(0, unusedEntries); - return ImmutableStylePropertySet::create(results.data(), results.size(), m_context.mode); + return ImmutableStyleProperties::create(results.data(), results.size(), m_context.mode); } void CSSParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit) @@ -1564,12 +1643,29 @@ void CSSParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtr CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId); if (prefixingVariant == propId) return; - addProperty(prefixingVariant, val.release(), important, implicit); + + if (m_currentShorthand) { + // We can't use ShorthandScope here as we can already be inside one (e.g we are parsing CSSTransition). + m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand); + addProperty(prefixingVariant, val.release(), important, implicit); + m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand); + } else + addProperty(prefixingVariant, val.release(), important, implicit); } void CSSParser::addProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit) { - m_parsedProperties.append(CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand || implicit)); + // This property doesn't belong to a shorthand or is a CSS variable (which will be resolved later). + if (!m_currentShorthand) { + m_parsedProperties.append(CSSProperty(propId, value, important, false, CSSPropertyInvalid, m_implicitShorthand || implicit)); + return; + } + + Vector<StylePropertyShorthand> shorthands = matchingShorthandsForLonghand(propId); + if (shorthands.size() == 1) + m_parsedProperties.append(CSSProperty(propId, value, important, true, CSSPropertyInvalid, m_implicitShorthand || implicit)); + else + m_parsedProperties.append(CSSProperty(propId, value, important, true, indexOfShorthandForLonghand(m_currentShorthand, shorthands), m_implicitShorthand || implicit)); } void CSSParser::rollbackLastProperties(int num) @@ -1583,99 +1679,102 @@ void CSSParser::clearProperties() { m_parsedProperties.clear(); m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES; - m_hasFontFaceOnlyValues = false; } -KURL CSSParser::completeURL(const CSSParserContext& context, const String& url) +URL CSSParser::completeURL(const CSSParserContext& context, const String& url) { if (url.isNull()) - return KURL(); + return URL(); if (context.charset.isEmpty()) - return KURL(context.baseURL, url); - return KURL(context.baseURL, url, context.charset); + return URL(context.baseURL, url); + return URL(context.baseURL, url, context.charset); } -KURL CSSParser::completeURL(const String& url) const +URL CSSParser::completeURL(const String& url) const { return completeURL(m_context, url); } -bool CSSParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc) +bool CSSParser::validateCalculationUnit(ValueWithCalculation& valueWithCalculation, Units unitFlags) { - bool mustBeNonNegative = unitflags & FNonNeg; + bool mustBeNonNegative = unitFlags & FNonNeg; - if (!parseCalculation(value, mustBeNonNegative ? CalculationRangeNonNegative : CalculationRangeAll)) - return false; + RefPtr<CSSCalcValue> calculation; + if (valueWithCalculation.calculation()) { + // The calculation value was already parsed so we reuse it. However, we may need to update its range. + calculation = valueWithCalculation.calculation(); + calculation->setPermittedValueRange(mustBeNonNegative ? CalculationRangeNonNegative : CalculationRangeAll); + } else { + valueWithCalculation.setCalculation(parseCalculation(valueWithCalculation, mustBeNonNegative ? CalculationRangeNonNegative : CalculationRangeAll)); + calculation = valueWithCalculation.calculation(); + if (!calculation) + return false; + } - bool b = false; - switch (m_parsedCalculation->category()) { + bool isValid = false; + switch (calculation->category()) { + case CalcNumber: + isValid = (unitFlags & FNumber); + if (!isValid && (unitFlags & FInteger) && calculation->isInt()) + isValid = true; + if (!isValid && (unitFlags & FPositiveInteger) && calculation->isInt() && calculation->isPositive()) + isValid = true; + break; case CalcLength: - b = (unitflags & FLength); + isValid = (unitFlags & FLength); break; case CalcPercent: - b = (unitflags & FPercent); - if (b && mustBeNonNegative && m_parsedCalculation->isNegative()) - b = false; - break; - case CalcNumber: - b = (unitflags & FNumber); - if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt()) - b = true; - if (b && mustBeNonNegative && m_parsedCalculation->isNegative()) - b = false; + isValid = (unitFlags & FPercent); break; case CalcPercentLength: - b = (unitflags & FPercent) && (unitflags & FLength); + isValid = (unitFlags & FPercent) && (unitFlags & FLength); break; case CalcPercentNumber: - b = (unitflags & FPercent) && (unitflags & FNumber); + isValid = (unitFlags & FPercent) && (unitFlags & FNumber); break; -#if ENABLE(CSS_VARIABLES) - case CalcVariable: - b = true; + case CalcAngle: + isValid = (unitFlags & FAngle); + break; + case CalcTime: + isValid = (unitFlags & FTime); + break; + case CalcFrequency: + isValid = (unitFlags & FFrequency); break; -#endif case CalcOther: break; } - if (!b || releaseCalc == ReleaseParsedCalcValue) - m_parsedCalculation.release(); - return b; + + return isValid; } -inline bool CSSParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode) +inline bool CSSParser::shouldAcceptUnitLessValues(CSSParserValue& value, Units unitFlags, CSSParserMode cssParserMode) { // Qirks mode and svg presentation attributes accept unit less values. - return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || cssParserMode == CSSQuirksMode || cssParserMode == SVGAttributeMode); + return (unitFlags & (FLength | FAngle | FTime)) && (!value.fValue || cssParserMode == CSSQuirksMode || cssParserMode == SVGAttributeMode); } -bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc) +bool CSSParser::validateUnit(ValueWithCalculation& valueWithCalculation, Units unitFlags, CSSParserMode cssParserMode) { - if (isCalculation(value)) - return validCalculationUnit(value, unitflags, releaseCalc); + if (isCalculation(valueWithCalculation)) + return validateCalculationUnit(valueWithCalculation, unitFlags); bool b = false; - switch (value->unit) { -#if ENABLE(CSS_VARIABLES) - case CSSPrimitiveValue::CSS_VARIABLE_NAME: - // Variables are checked at the point they are dereferenced because unit type is not available here. - b = true; - break; -#endif + switch (valueWithCalculation.value().unit) { case CSSPrimitiveValue::CSS_NUMBER: - b = (unitflags & FNumber); - if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) { - value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX : - ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS); + b = (unitFlags & FNumber); + if (!b && shouldAcceptUnitLessValues(valueWithCalculation, unitFlags, cssParserMode)) { + valueWithCalculation.value().unit = (unitFlags & FLength) ? CSSPrimitiveValue::CSS_PX : + ((unitFlags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS); b = true; } - if (!b && (unitflags & FInteger) && value->isInt) + if (!b && (unitFlags & FInteger) && valueWithCalculation.value().isInt) b = true; - if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0) + if (!b && (unitFlags & FPositiveInteger) && valueWithCalculation.value().isInt && valueWithCalculation.value().fValue > 0) b = true; break; case CSSPrimitiveValue::CSS_PERCENTAGE: - b = (unitflags & FPercent); + b = (unitFlags & FPercent); break; case CSSParserValue::Q_EMS: case CSSPrimitiveValue::CSS_EMS: @@ -1692,23 +1791,23 @@ bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode case CSSPrimitiveValue::CSS_VH: case CSSPrimitiveValue::CSS_VMIN: case CSSPrimitiveValue::CSS_VMAX: - b = (unitflags & FLength); + b = (unitFlags & FLength); break; case CSSPrimitiveValue::CSS_MS: case CSSPrimitiveValue::CSS_S: - b = (unitflags & FTime); + b = (unitFlags & FTime); break; case CSSPrimitiveValue::CSS_DEG: case CSSPrimitiveValue::CSS_RAD: case CSSPrimitiveValue::CSS_GRAD: case CSSPrimitiveValue::CSS_TURN: - b = (unitflags & FAngle); + b = (unitFlags & FAngle); break; #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) case CSSPrimitiveValue::CSS_DPPX: case CSSPrimitiveValue::CSS_DPI: case CSSPrimitiveValue::CSS_DPCM: - b = (unitflags & FResolution); + b = (unitFlags & FResolution); break; #endif case CSSPrimitiveValue::CSS_HZ: @@ -1717,104 +1816,79 @@ bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode default: break; } - if (b && unitflags & FNonNeg && value->fValue < 0) + if (b && unitFlags & FNonNeg && valueWithCalculation.value().fValue < 0) + b = false; + if (b && std::isinf(valueWithCalculation.value().fValue)) b = false; return b; } -inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveNumericValue(CSSParserValue* value) +inline Ref<CSSPrimitiveValue> CSSParser::createPrimitiveNumericValue(ValueWithCalculation& valueWithCalculation) { -#if ENABLE(CSS_VARIABLES) - if (value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME) - return createPrimitiveVariableNameValue(value); -#endif - - if (m_parsedCalculation) { - ASSERT(isCalculation(value)); - return CSSPrimitiveValue::create(m_parsedCalculation.release()); - } + if (valueWithCalculation.calculation()) + return CSSPrimitiveValue::create(valueWithCalculation.calculation()); + CSSParserValue& value = valueWithCalculation; #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) - ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) - || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS) - || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX) - || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)); + ASSERT((value.unit >= CSSPrimitiveValue::CSS_NUMBER && value.unit <= CSSPrimitiveValue::CSS_KHZ) + || (value.unit >= CSSPrimitiveValue::CSS_TURN && value.unit <= CSSPrimitiveValue::CSS_CHS) + || (value.unit >= CSSPrimitiveValue::CSS_VW && value.unit <= CSSPrimitiveValue::CSS_VMAX) + || (value.unit >= CSSPrimitiveValue::CSS_DPPX && value.unit <= CSSPrimitiveValue::CSS_DPCM)); #else - ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) - || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS) - || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)); + ASSERT((value.unit >= CSSPrimitiveValue::CSS_NUMBER && value.unit <= CSSPrimitiveValue::CSS_KHZ) + || (value.unit >= CSSPrimitiveValue::CSS_TURN && value.unit <= CSSPrimitiveValue::CSS_CHS) + || (value.unit >= CSSPrimitiveValue::CSS_VW && value.unit <= CSSPrimitiveValue::CSS_VMAX)); #endif - return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)); -} - -inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveStringValue(CSSParserValue* value) -{ - ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT); - return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING); + return CSSValuePool::singleton().createValue(value.fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value.unit)); } -#if ENABLE(CSS_VARIABLES) -inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveVariableNameValue(CSSParserValue* value) +inline Ref<CSSPrimitiveValue> CSSParser::createPrimitiveStringValue(CSSParserValue& value) { - ASSERT(value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME); - return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_VARIABLE_NAME); + ASSERT(value.unit == CSSPrimitiveValue::CSS_STRING || value.unit == CSSPrimitiveValue::CSS_IDENT); + return CSSValuePool::singleton().createValue(value.string, CSSPrimitiveValue::CSS_STRING); } -#endif static inline bool isComma(CSSParserValue* value) { return value && value->unit == CSSParserValue::Operator && value->iValue == ','; } -static inline bool isForwardSlashOperator(CSSParserValue* value) +static inline bool isForwardSlashOperator(CSSParserValue& value) { - ASSERT(value); - return value->unit == CSSParserValue::Operator && value->iValue == '/'; + return value.unit == CSSParserValue::Operator && value.iValue == '/'; } -bool CSSParser::validWidth(CSSParserValue* value) +bool CSSParser::isValidSize(ValueWithCalculation& valueWithCalculation) { - int id = value->id; + int id = valueWithCalculation.value().id; if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent) return true; - return !id && validUnit(value, FLength | FPercent | FNonNeg); -} - -// FIXME: Combine this with validWidth when we support fit-content, et al, for heights. -bool CSSParser::validHeight(CSSParserValue* value) -{ - int id = value->id; - if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) - return true; - return !id && validUnit(value, FLength | FPercent | FNonNeg); + return !id && validateUnit(valueWithCalculation, FLength | FPercent | FNonNeg); } -inline PassRefPtr<CSSPrimitiveValue> CSSParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value) +inline RefPtr<CSSPrimitiveValue> CSSParser::parseValidPrimitive(CSSValueID identifier, ValueWithCalculation& valueWithCalculation) { if (identifier) - return cssValuePool().createIdentifierValue(identifier); - if (value->unit == CSSPrimitiveValue::CSS_STRING) - return createPrimitiveStringValue(value); - if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) - return createPrimitiveNumericValue(value); - if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS) - return createPrimitiveNumericValue(value); - if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX) - return createPrimitiveNumericValue(value); + return CSSValuePool::singleton().createIdentifierValue(identifier); + + if (valueWithCalculation.value().unit == CSSPrimitiveValue::CSS_STRING) + return createPrimitiveStringValue(valueWithCalculation); + if (valueWithCalculation.value().unit >= CSSPrimitiveValue::CSS_NUMBER && valueWithCalculation.value().unit <= CSSPrimitiveValue::CSS_KHZ) + return createPrimitiveNumericValue(valueWithCalculation); + if (valueWithCalculation.value().unit >= CSSPrimitiveValue::CSS_TURN && valueWithCalculation.value().unit <= CSSPrimitiveValue::CSS_CHS) + return createPrimitiveNumericValue(valueWithCalculation); + if (valueWithCalculation.value().unit >= CSSPrimitiveValue::CSS_VW && valueWithCalculation.value().unit <= CSSPrimitiveValue::CSS_VMAX) + return createPrimitiveNumericValue(valueWithCalculation); #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) - if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM) - return createPrimitiveNumericValue(value); -#endif -#if ENABLE(CSS_VARIABLES) - if (value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME) - return createPrimitiveVariableNameValue(value); + if (valueWithCalculation.value().unit >= CSSPrimitiveValue::CSS_DPPX && valueWithCalculation.value().unit <= CSSPrimitiveValue::CSS_DPCM) + return createPrimitiveNumericValue(valueWithCalculation); #endif - if (value->unit >= CSSParserValue::Q_EMS) - return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS); - if (isCalculation(value)) - return CSSPrimitiveValue::create(m_parsedCalculation.release()); + if (valueWithCalculation.value().unit >= CSSParserValue::Q_EMS) + return CSSPrimitiveValue::createAllowingMarginQuirk(valueWithCalculation.value().fValue, CSSPrimitiveValue::CSS_EMS); + if (valueWithCalculation.calculation()) + return CSSPrimitiveValue::create(valueWithCalculation.calculation()); - return 0; + return nullptr; } void CSSParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtr<CSSValue> prpValue, bool important) @@ -1833,52 +1907,73 @@ void CSSParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtr<CSS addProperty(longhands[i], value, important); } -bool CSSParser::parseValue(CSSPropertyID propId, bool important) +RefPtr<CSSValue> CSSParser::parseVariableDependentValue(CSSPropertyID propID, const CSSVariableDependentValue& dependentValue, const CustomPropertyValueMap& customProperties) { - if (!m_valueList) - return false; - - CSSParserValue* value = m_valueList->current(); + m_valueList.reset(new CSSParserValueList()); + if (!dependentValue.valueList()->buildParserValueListSubstitutingVariables(m_valueList.get(), customProperties)) + return nullptr; + bool parsed = parseValue(dependentValue.propertyID(), false); + if (!parsed) + return nullptr; + for (size_t i = 0; i < m_parsedProperties.size(); ++i) { + if (m_parsedProperties[i].id() == propID) + return m_parsedProperties[i].value(); + } + return nullptr; +} - if (!value) +bool CSSParser::parseValue(CSSPropertyID propId, bool important) +{ + if (!m_valueList || !m_valueList->current()) return false; - - // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function. - // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers. - ASSERT(!m_parsedCalculation); - CSSValueID id = value->id; + ValueWithCalculation valueWithCalculation(*m_valueList->current()); + CSSValueID id = valueWithCalculation.value().id; + + if (propId == CSSPropertyCustom) + return parseCustomPropertyDeclaration(important, id); - int num = inShorthand() ? 1 : m_valueList->size(); + if (m_valueList->containsVariables()) { + RefPtr<CSSValueList> valueList = CSSValueList::createFromParserValueList(*m_valueList); + addExpandedPropertyForValue(propId, CSSVariableDependentValue::create(valueList, propId), important); + return true; + } + + auto& cssValuePool = CSSValuePool::singleton(); + unsigned num = inShorthand() ? 1 : m_valueList->size(); if (id == CSSValueInherit) { if (num != 1) return false; - addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important); + addExpandedPropertyForValue(propId, cssValuePool.createInheritedValue(), important); return true; } else if (id == CSSValueInitial) { if (num != 1) return false; - addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important); + addExpandedPropertyForValue(propId, cssValuePool.createExplicitInitialValue(), important); return true; - } - -#if ENABLE(CSS_VARIABLES) - if (!id && value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME && num == 1) { - addProperty(propId, createPrimitiveVariableNameValue(value), important); - m_valueList->next(); + } else if (id == CSSValueUnset) { + if (num != 1) + return false; + addExpandedPropertyForValue(propId, cssValuePool.createUnsetValue(), important); + return true; + } else if (id == CSSValueRevert) { + if (num != 1) + return false; + addExpandedPropertyForValue(propId, cssValuePool.createRevertValue(), important); return true; } - ASSERT(propId != CSSPropertyVariable); -#endif + + if (propId == CSSPropertyAll) + return false; // "all" doesn't allow you to specify anything other than inherit/initial/unset. if (isKeywordPropertyID(propId)) { - if (!isValidKeywordPropertyAndValue(propId, id, m_context)) + if (!isValidKeywordPropertyAndValue(propId, id, m_context, m_styleSheet)) return false; if (m_valueList->next() && !inShorthand()) return false; - addProperty(propId, cssValuePool().createIdentifierValue(id), important); + addProperty(propId, cssValuePool.createIdentifierValue(id), important); return true; } @@ -1895,7 +1990,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) return parseSize(propId, important); case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit - if (id) + if (id == CSSValueNone) validPrimitive = true; else return parseQuotes(propId, important); @@ -1914,10 +2009,13 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) // close-quote | no-open-quote | no-close-quote ]+ | inherit return parseContent(propId, important); + case CSSPropertyAlt: // [ <string> | attr(X) ] + return parseAlt(propId, important); + case CSSPropertyClip: // <shape> | auto | inherit if (id == CSSValueAuto) validPrimitive = true; - else if (value->unit == CSSParserValue::Function) + else if (valueWithCalculation.value().unit == CSSParserValue::Function) return parseClipShape(propId, important); break; @@ -1936,7 +2034,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) // pagination controls, it should default to hidden. If the overflow-y value is anything but // paged-x or paged-y, then overflow-x and overflow-y should have the same value. if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY) - overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto); + overflowXValue = cssValuePool.createIdentifierValue(CSSValueAuto); else overflowXValue = m_parsedProperties.last().value(); addProperty(CSSPropertyOverflowX, overflowXValue.release(), important); @@ -1956,6 +2054,10 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) return false; return parseFontWeight(important); } + + case CSSPropertyFontSynthesis: // none | [ weight || style ] + return parseFontSynthesis(important); + case CSSPropertyBorderSpacing: { if (num == 1) { ShorthandScope scope(this, CSSPropertyBorderSpacing); @@ -1975,7 +2077,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) } case CSSPropertyWebkitBorderHorizontalSpacing: case CSSPropertyWebkitBorderVerticalSpacing: - validPrimitive = validUnit(value, FLength | FNonNeg); + validPrimitive = validateUnit(valueWithCalculation, FLength | FNonNeg); break; case CSSPropertyOutlineColor: // <color> | invert | inherit // Outline color has "invert" as additional keyword. @@ -1984,7 +2086,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) validPrimitive = true; break; } - /* nobreak */ + FALLTHROUGH; case CSSPropertyBackgroundColor: // <color> | inherit case CSSPropertyBorderTopColor: // <color> | inherit case CSSPropertyBorderRightColor: @@ -1998,10 +2100,8 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors case CSSPropertyTextUnderlineColor: case CSSPropertyTextOverlineColor: - case CSSPropertyWebkitColumnRuleColor: -#if ENABLE(CSS3_TEXT) + case CSSPropertyColumnRuleColor: case CSSPropertyWebkitTextDecorationColor: -#endif // CSS3_TEXT case CSSPropertyWebkitTextEmphasisColor: case CSSPropertyWebkitTextFillColor: case CSSPropertyWebkitTextStrokeColor: @@ -2010,8 +2110,8 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) // since we use this in our UA sheets. else if (id == CSSValueCurrentcolor) validPrimitive = true; - else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || - (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) { + else if (isValidSystemColorValue(id) || id == CSSValueMenu + || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) { validPrimitive = true; } else { parsedValue = parseColor(); @@ -2026,17 +2126,19 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize | // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize | // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help | - // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in - // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit + // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | + // zoom-in | zoom-out | all-scroll | -webkit-grab | -webkit-grabbing | -webkit-zoom-in | + // -webkit-zoom-out ] ] | inherit RefPtr<CSSValueList> list; + CSSParserValue* value = &valueWithCalculation.value(); while (value) { - RefPtr<CSSValue> image = 0; + RefPtr<CSSValue> image; if (value->unit == CSSPrimitiveValue::CSS_URI) { String uri = value->string; if (!uri.isNull()) image = CSSImageValue::create(completeURL(uri)); #if ENABLE(CSS_IMAGE_SET) && ENABLE(MOUSE_CURSOR_SCALE) - } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) { + } else if (value->unit == CSSParserValue::Function && equalLettersIgnoringASCIICase(value->function->name, "-webkit-image-set(")) { image = parseImageSet(); if (!image) break; @@ -2064,29 +2166,31 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) list = CSSValueList::createCommaSeparated(); if (image) - list->append(CSSCursorImageValue::create(image, hasHotSpot, hotSpot)); + list->append(CSSCursorImageValue::create(image.releaseNonNull(), hasHotSpot, hotSpot)); if ((inStrictMode() && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ','))) return false; value = m_valueList->next(); // comma } if (list) { - if (!value) { // no value after url list (MSIE 5 compatibility) + if (!value) { + // no value after url list (MSIE 5 compatibility) if (list->length() != 1) return false; } else if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/ - list->append(cssValuePool().createIdentifierValue(CSSValuePointer)); - else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone) - list->append(cssValuePool().createIdentifierValue(value->id)); + list->append(cssValuePool.createIdentifierValue(CSSValuePointer)); + else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitZoomOut) || value->id == CSSValueCopy || value->id == CSSValueNone) + list->append(cssValuePool.createIdentifierValue(value->id)); m_valueList->next(); parsedValue = list.release(); break; } else if (value) { id = value->id; - if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/ + if (inQuirksMode() && value->id == CSSValueHand) { + // MSIE 5 compatibility :/ id = CSSValuePointer; validPrimitive = true; - } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone) + } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitZoomOut) || value->id == CSSValueCopy || value->id == CSSValueNone) validPrimitive = true; } else { ASSERT_NOT_REACHED(); @@ -2103,7 +2207,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) #endif case CSSPropertyBackgroundAttachment: - case CSSPropertyWebkitBackgroundBlendMode: + case CSSPropertyBackgroundBlendMode: case CSSPropertyBackgroundClip: case CSSPropertyWebkitBackgroundClip: case CSSPropertyWebkitBackgroundComposite: @@ -2126,6 +2230,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyWebkitMaskPositionX: case CSSPropertyWebkitMaskPositionY: case CSSPropertyWebkitMaskSize: + case CSSPropertyWebkitMaskSourceType: case CSSPropertyWebkitMaskRepeat: case CSSPropertyWebkitMaskRepeatX: case CSSPropertyWebkitMaskRepeatY: @@ -2135,12 +2240,12 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) CSSPropertyID propId1, propId2; bool result = false; if (parseFillProperty(propId, propId1, propId2, val1, val2)) { - OwnPtr<ShorthandScope> shorthandScope; + std::unique_ptr<ShorthandScope> shorthandScope; if (propId == CSSPropertyBackgroundPosition || propId == CSSPropertyBackgroundRepeat || propId == CSSPropertyWebkitMaskPosition || propId == CSSPropertyWebkitMaskRepeat) { - shorthandScope = adoptPtr(new ShorthandScope(this, propId)); + shorthandScope = std::make_unique<ShorthandScope>(this, propId); } addProperty(propId1, val1.release(), important); if (val2) @@ -2154,19 +2259,19 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyBorderImageSource: case CSSPropertyWebkitMaskBoxImageSource: if (id == CSSValueNone) { - parsedValue = cssValuePool().createIdentifierValue(CSSValueNone); + parsedValue = cssValuePool.createIdentifierValue(CSSValueNone); m_valueList->next(); - } else if (value->unit == CSSPrimitiveValue::CSS_URI) { - parsedValue = CSSImageValue::create(completeURL(value->string)); + } else if (valueWithCalculation.value().unit == CSSPrimitiveValue::CSS_URI) { + parsedValue = CSSImageValue::create(completeURL(valueWithCalculation.value().string)); m_valueList->next(); - } else if (isGeneratedImageValue(value)) { - if (parseGeneratedImage(m_valueList.get(), parsedValue)) + } else if (isGeneratedImageValue(valueWithCalculation)) { + if (parseGeneratedImage(*m_valueList, parsedValue)) m_valueList->next(); else return false; } #if ENABLE(CSS_IMAGE_SET) - else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) { + else if (valueWithCalculation.value().unit == CSSParserValue::Function && equalLettersIgnoringASCIICase(valueWithCalculation.value().function->name, "-webkit-image-set(")) { parsedValue = parseImageSet(); if (!parsedValue) return false; @@ -2185,19 +2290,25 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyWebkitBorderEndWidth: case CSSPropertyWebkitBorderBeforeWidth: case CSSPropertyWebkitBorderAfterWidth: - case CSSPropertyWebkitColumnRuleWidth: + case CSSPropertyColumnRuleWidth: if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick) validPrimitive = true; else - validPrimitive = validUnit(value, FLength | FNonNeg); + validPrimitive = validateUnit(valueWithCalculation, FLength | FNonNeg); break; case CSSPropertyLetterSpacing: // normal | <length> | inherit - case CSSPropertyWordSpacing: // normal | <length> | inherit if (id == CSSValueNormal) validPrimitive = true; else - validPrimitive = validUnit(value, FLength); + validPrimitive = validateUnit(valueWithCalculation, FLength); + break; + + case CSSPropertyWordSpacing: // normal | <length> | <percentage> | inherit + if (id == CSSValueNormal) + validPrimitive = true; + else + validPrimitive = validateUnit(valueWithCalculation, FLength | FPercent); break; case CSSPropertyTextIndent: @@ -2212,45 +2323,33 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyWebkitPaddingEnd: case CSSPropertyWebkitPaddingBefore: case CSSPropertyWebkitPaddingAfter: - validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg)); + validPrimitive = (!id && validateUnit(valueWithCalculation, FLength | FPercent | FNonNeg)); break; case CSSPropertyMaxWidth: case CSSPropertyWebkitMaxLogicalWidth: - validPrimitive = (id == CSSValueNone || validWidth(value)); - break; - - case CSSPropertyMinWidth: - case CSSPropertyWebkitMinLogicalWidth: - validPrimitive = validWidth(value); - break; - - case CSSPropertyWidth: - case CSSPropertyWebkitLogicalWidth: - validPrimitive = (id == CSSValueAuto || validWidth(value)); - break; - case CSSPropertyMaxHeight: case CSSPropertyWebkitMaxLogicalHeight: - validPrimitive = (id == CSSValueNone || validHeight(value)); + validPrimitive = (id == CSSValueNone || isValidSize(valueWithCalculation)); break; + case CSSPropertyMinWidth: + case CSSPropertyWebkitMinLogicalWidth: case CSSPropertyMinHeight: case CSSPropertyWebkitMinLogicalHeight: - validPrimitive = validHeight(value); + validPrimitive = id == CSSValueAuto || isValidSize(valueWithCalculation); break; + case CSSPropertyWidth: + case CSSPropertyWebkitLogicalWidth: case CSSPropertyHeight: case CSSPropertyWebkitLogicalHeight: - validPrimitive = (id == CSSValueAuto || validHeight(value)); + validPrimitive = (id == CSSValueAuto || isValidSize(valueWithCalculation)); break; case CSSPropertyFontSize: return parseFontSize(important); - case CSSPropertyFontVariant: // normal | small-caps | inherit - return parseFontVariant(important); - case CSSPropertyVerticalAlign: // baseline | sub | super | top | text-top | middle | bottom | text-bottom | // <percentage> | <length> | inherit @@ -2258,7 +2357,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle) validPrimitive = true; else - validPrimitive = (!id && validUnit(value, FLength | FPercent)); + validPrimitive = (!id && validateUnit(valueWithCalculation, FLength | FPercent)); break; case CSSPropertyBottom: // <length> | <percentage> | auto | inherit @@ -2276,21 +2375,22 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) if (id == CSSValueAuto) validPrimitive = true; else - validPrimitive = (!id && validUnit(value, FLength | FPercent)); + validPrimitive = (!id && validateUnit(valueWithCalculation, FLength | FPercent)); break; case CSSPropertyZIndex: // auto | <integer> | inherit - if (id == CSSValueAuto) { + if (id == CSSValueAuto) validPrimitive = true; - break; - } - /* nobreak */ + else + validPrimitive = (!id && validateUnit(valueWithCalculation, FInteger, CSSQuirksMode)); + break; + case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility) case CSSPropertyWidows: // <integer> | inherit | auto (Ditto) if (id == CSSValueAuto) validPrimitive = true; else - validPrimitive = (!id && validUnit(value, FInteger, CSSQuirksMode)); + validPrimitive = (!id && validateUnit(valueWithCalculation, FPositiveInteger, CSSQuirksMode)); break; case CSSPropertyLineHeight: @@ -2312,53 +2412,47 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) break; } + case CSSPropertyWebkitTextDecoration: + // [ <text-decoration-line> || <text-decoration-style> || <text-decoration-color> ] | inherit + return parseShorthand(CSSPropertyWebkitTextDecoration, webkitTextDecorationShorthand(), important); + case CSSPropertyTextDecoration: case CSSPropertyWebkitTextDecorationsInEffect: -#if ENABLE(CSS3_TEXT) case CSSPropertyWebkitTextDecorationLine: -#endif // CSS3_TEXT // none | [ underline || overline || line-through || blink ] | inherit return parseTextDecoration(propId, important); -#if ENABLE(CSS3_TEXT) case CSSPropertyWebkitTextDecorationStyle: // solid | double | dotted | dashed | wavy if (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDotted || id == CSSValueDashed || id == CSSValueWavy) validPrimitive = true; break; + case CSSPropertyWebkitTextDecorationSkip: + // none | [ objects || spaces || ink || edges || box-decoration ] + return parseTextDecorationSkip(important); + case CSSPropertyWebkitTextUnderlinePosition: // auto | alphabetic | under return parseTextUnderlinePosition(important); -#endif // CSS3_TEXT - case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit + case CSSPropertyZoom: + // normal | reset | document | <number> | <percentage> | inherit if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument) validPrimitive = true; else - validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode)); + validPrimitive = (!id && validateUnit(valueWithCalculation, FNumber | FPercent | FNonNeg, CSSStrictMode)); + break; + + case CSSPropertyWebkitTextZoom: + // normal | reset + if (id == CSSValueNormal || id == CSSValueReset) + validPrimitive = true; break; case CSSPropertySrc: // Only used within @font-face and @-webkit-filter, so cannot use inherit | initial or be !important. This is a list of urls or local references. -#if ENABLE(CSS_SHADERS) - if (m_inFilterRule) - return parseFilterRuleSrc(); -#endif return parseFontFaceSrc(); -#if ENABLE(CSS_SHADERS) - case CSSPropertyMix: - // The mix property is just supported inside of an @filter rule. - if (!m_inFilterRule) - return false; - return parseFilterRuleMix(); - case CSSPropertyParameters: - // The parameters property is just supported inside of an @filter rule. - if (!m_inFilterRule) - return false; - return parseFilterRuleParameters(); -#endif - case CSSPropertyUnicodeRange: return parseFontFaceUnicodeRange(); @@ -2419,17 +2513,17 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyBorderBottomRightRadius: { if (num != 1 && num != 2) return false; - validPrimitive = validUnit(value, FLength | FPercent | FNonNeg); + validPrimitive = validateUnit(valueWithCalculation, FLength | FPercent | FNonNeg); if (!validPrimitive) return false; - RefPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value); + RefPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(valueWithCalculation); RefPtr<CSSPrimitiveValue> parsedValue2; if (num == 2) { - value = m_valueList->next(); - validPrimitive = validUnit(value, FLength | FPercent | FNonNeg); + ValueWithCalculation nextValueWithCalculation(*m_valueList->next()); + validPrimitive = validateUnit(nextValueWithCalculation, FLength | FPercent | FNonNeg); if (!validPrimitive) return false; - parsedValue2 = createPrimitiveNumericValue(value); + parsedValue2 = createPrimitiveNumericValue(nextValueWithCalculation); } else parsedValue2 = parsedValue1; @@ -2437,7 +2531,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) return true; } case CSSPropertyTabSize: - validPrimitive = validUnit(value, FInteger | FNonNeg); + validPrimitive = validateUnit(valueWithCalculation, FInteger | FNonNeg); break; case CSSPropertyWebkitAspectRatio: return parseAspectRatio(important); @@ -2445,7 +2539,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyWebkitBorderRadius: return parseBorderRadius(propId, important); case CSSPropertyOutlineOffset: - validPrimitive = validUnit(value, FLength | FPercent); + validPrimitive = validateUnit(valueWithCalculation, FLength); break; case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3 case CSSPropertyBoxShadow: @@ -2453,7 +2547,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) if (id == CSSValueNone) validPrimitive = true; else { - RefPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId); + RefPtr<CSSValueList> shadowValueList = parseShadow(*m_valueList, propId); if (shadowValueList) { addProperty(propId, shadowValueList.release(), important); m_valueList->next(); @@ -2462,6 +2556,30 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) return false; } break; + case CSSPropertyWebkitInitialLetter: { + if (id == CSSValueNormal) + validPrimitive = true; + else { + if (num != 1 && num != 2) + return false; + validPrimitive = validateUnit(valueWithCalculation, FPositiveInteger); + if (!validPrimitive) + return false; + RefPtr<CSSPrimitiveValue> height = createPrimitiveNumericValue(valueWithCalculation); + RefPtr<CSSPrimitiveValue> position; + if (num == 2) { + ValueWithCalculation nextValueWithCalculation(*m_valueList->next()); + validPrimitive = validateUnit(nextValueWithCalculation, FPositiveInteger); + if (!validPrimitive) + return false; + position = createPrimitiveNumericValue(nextValueWithCalculation); + } else + position = height; + addProperty(propId, createPrimitiveValuePair(position.release(), height.release()), important); + return true; + } + break; + } case CSSPropertyWebkitBoxReflect: if (id == CSSValueNone) validPrimitive = true; @@ -2469,63 +2587,67 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) return parseReflect(propId, important); break; case CSSPropertyOpacity: - validPrimitive = validUnit(value, FNumber); + validPrimitive = validateUnit(valueWithCalculation, FNumber); break; case CSSPropertyWebkitBoxFlex: - validPrimitive = validUnit(value, FNumber); + validPrimitive = validateUnit(valueWithCalculation, FNumber); break; case CSSPropertyWebkitBoxFlexGroup: - validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode); + validPrimitive = validateUnit(valueWithCalculation, FInteger | FNonNeg, CSSStrictMode); break; case CSSPropertyWebkitBoxOrdinalGroup: - validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode) && value->fValue; + validPrimitive = validateUnit(valueWithCalculation, FInteger | FNonNeg, CSSStrictMode) && valueWithCalculation.value().fValue; break; -#if ENABLE(CSS_FILTERS) - case CSSPropertyWebkitFilter: + case CSSPropertyFilter: +#if ENABLE(FILTERS_LEVEL_2) + case CSSPropertyWebkitBackdropFilter: +#endif if (id == CSSValueNone) validPrimitive = true; else { - RefPtr<CSSValue> val = parseFilter(); - if (val) { - addProperty(propId, val, important); - return true; - } - return false; + RefPtr<CSSValue> currValue; + if (!parseFilter(*m_valueList, currValue)) + return false; + addProperty(propId, currValue, important); + return true; } break; -#endif #if ENABLE(CSS_COMPOSITING) - case CSSPropertyWebkitBlendMode: + case CSSPropertyMixBlendMode: + if (cssCompositingEnabled()) + validPrimitive = true; + break; + case CSSPropertyIsolation: if (cssCompositingEnabled()) validPrimitive = true; break; #endif - case CSSPropertyWebkitFlex: { + case CSSPropertyFlex: { ShorthandScope scope(this, propId); if (id == CSSValueNone) { - addProperty(CSSPropertyWebkitFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important); - addProperty(CSSPropertyWebkitFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important); - addProperty(CSSPropertyWebkitFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important); + addProperty(CSSPropertyFlexGrow, cssValuePool.createValue(0, CSSPrimitiveValue::CSS_NUMBER), important); + addProperty(CSSPropertyFlexShrink, cssValuePool.createValue(0, CSSPrimitiveValue::CSS_NUMBER), important); + addProperty(CSSPropertyFlexBasis, cssValuePool.createIdentifierValue(CSSValueAuto), important); return true; } - return parseFlex(m_valueList.get(), important); + return parseFlex(*m_valueList, important); } - case CSSPropertyWebkitFlexBasis: + case CSSPropertyFlexBasis: // FIXME: Support intrinsic dimensions too. if (id == CSSValueAuto) validPrimitive = true; else - validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg)); + validPrimitive = (!id && validateUnit(valueWithCalculation, FLength | FPercent | FNonNeg)); break; - case CSSPropertyWebkitFlexGrow: - case CSSPropertyWebkitFlexShrink: - validPrimitive = validUnit(value, FNumber | FNonNeg); + case CSSPropertyFlexGrow: + case CSSPropertyFlexShrink: + validPrimitive = validateUnit(valueWithCalculation, FNumber | FNonNeg); break; - case CSSPropertyWebkitOrder: - if (validUnit(value, FInteger, CSSStrictMode)) { + case CSSPropertyOrder: + if (validateUnit(valueWithCalculation, FInteger, CSSStrictMode)) { // We restrict the smallest value to int min + 2 because we use int min and int min + 1 as special values in a hash set. - parsedValue = cssValuePool().createValue(max(static_cast<double>(std::numeric_limits<int>::min() + 2), value->fValue), - static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)); + double result = std::max<double>(std::numeric_limits<int>::min() + 2, parsedDouble(valueWithCalculation)); + parsedValue = cssValuePool.createValue(result, CSSPrimitiveValue::CSS_NUMBER); m_valueList->next(); } break; @@ -2535,19 +2657,19 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium) validPrimitive = true; else - validPrimitive = validUnit(value, FLength | FPercent); + validPrimitive = validateUnit(valueWithCalculation, FLength | FPercent); break; case CSSPropertyWebkitMarqueeRepetition: if (id == CSSValueInfinite) validPrimitive = true; else - validPrimitive = validUnit(value, FInteger | FNonNeg); + validPrimitive = validateUnit(valueWithCalculation, FInteger | FNonNeg); break; case CSSPropertyWebkitMarqueeSpeed: if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast) validPrimitive = true; else - validPrimitive = validUnit(value, FTime | FInteger | FNonNeg); + validPrimitive = validateUnit(valueWithCalculation, FTime | FInteger | FNonNeg); break; #if ENABLE(CSS_REGIONS) case CSSPropertyWebkitFlowInto: @@ -2559,7 +2681,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) return false; return parseRegionThread(propId, important); #endif - case CSSPropertyWebkitTransform: + case CSSPropertyTransform: if (id == CSSValueNone) validPrimitive = true; else { @@ -2571,12 +2693,12 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) return false; } break; - case CSSPropertyWebkitTransformOrigin: - case CSSPropertyWebkitTransformOriginX: - case CSSPropertyWebkitTransformOriginY: - case CSSPropertyWebkitTransformOriginZ: { - RefPtr<CSSValue> val1; - RefPtr<CSSValue> val2; + case CSSPropertyTransformOrigin: + case CSSPropertyTransformOriginX: + case CSSPropertyTransformOriginY: + case CSSPropertyTransformOriginZ: { + RefPtr<CSSPrimitiveValue> val1; + RefPtr<CSSPrimitiveValue> val2; RefPtr<CSSValue> val3; CSSPropertyID propId1, propId2, propId3; if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) { @@ -2589,13 +2711,13 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) } return false; } - case CSSPropertyWebkitPerspective: + case CSSPropertyPerspective: if (id == CSSValueNone) validPrimitive = true; else { // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property. - if (validUnit(value, FNumber | FLength | FNonNeg)) { - RefPtr<CSSValue> val = createPrimitiveNumericValue(value); + if (validateUnit(valueWithCalculation, FNumber | FLength | FNonNeg)) { + RefPtr<CSSValue> val = createPrimitiveNumericValue(valueWithCalculation); if (val) { addProperty(propId, val.release(), important); return true; @@ -2604,11 +2726,11 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) } } break; - case CSSPropertyWebkitPerspectiveOrigin: - case CSSPropertyWebkitPerspectiveOriginX: - case CSSPropertyWebkitPerspectiveOriginY: { - RefPtr<CSSValue> val1; - RefPtr<CSSValue> val2; + case CSSPropertyPerspectiveOrigin: + case CSSPropertyPerspectiveOriginX: + case CSSPropertyPerspectiveOriginY: { + RefPtr<CSSPrimitiveValue> val1; + RefPtr<CSSPrimitiveValue> val2; CSSPropertyID propId1, propId2; if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) { addProperty(propId1, val1.release(), important); @@ -2618,6 +2740,14 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) } return false; } + case CSSPropertyAnimationDelay: + case CSSPropertyAnimationDirection: + case CSSPropertyAnimationDuration: + case CSSPropertyAnimationFillMode: + case CSSPropertyAnimationName: + case CSSPropertyAnimationPlayState: + case CSSPropertyAnimationIterationCount: + case CSSPropertyAnimationTimingFunction: case CSSPropertyWebkitAnimationDelay: case CSSPropertyWebkitAnimationDirection: case CSSPropertyWebkitAnimationDuration: @@ -2626,6 +2756,9 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyWebkitAnimationPlayState: case CSSPropertyWebkitAnimationIterationCount: case CSSPropertyWebkitAnimationTimingFunction: +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + case CSSPropertyWebkitAnimationTrigger: +#endif case CSSPropertyTransitionDelay: case CSSPropertyTransitionDuration: case CSSPropertyTransitionTimingFunction: @@ -2642,38 +2775,63 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) } return false; } - + case CSSPropertyJustifyContent: + parsedValue = parseContentDistributionOverflowPosition(); + break; + case CSSPropertyJustifySelf: + return parseItemPositionOverflowPosition(propId, important); + case CSSPropertyJustifyItems: + if (parseLegacyPosition(propId, important)) + return true; + m_valueList->setCurrentIndex(0); + return parseItemPositionOverflowPosition(propId, important); +#if ENABLE(CSS_GRID_LAYOUT) case CSSPropertyWebkitGridAutoColumns: case CSSPropertyWebkitGridAutoRows: - if (!cssGridLayoutEnabled()) - return false; - parsedValue = parseGridTrackSize(); + parsedValue = parseGridTrackSize(*m_valueList); break; - case CSSPropertyWebkitGridDefinitionColumns: - case CSSPropertyWebkitGridDefinitionRows: - if (!cssGridLayoutEnabled()) - return false; - return parseGridTrackList(propId, important); + case CSSPropertyWebkitGridTemplateColumns: + case CSSPropertyWebkitGridTemplateRows: + parsedValue = parseGridTrackList(); + break; - case CSSPropertyWebkitGridStart: - case CSSPropertyWebkitGridEnd: - case CSSPropertyWebkitGridBefore: - case CSSPropertyWebkitGridAfter: - if (!cssGridLayoutEnabled()) - return false; + case CSSPropertyWebkitGridColumnStart: + case CSSPropertyWebkitGridColumnEnd: + case CSSPropertyWebkitGridRowStart: + case CSSPropertyWebkitGridRowEnd: + parsedValue = parseGridPosition(); + break; - validPrimitive = id == CSSValueAuto || (validUnit(value, FInteger) && value->fValue); + case CSSPropertyWebkitGridColumnGap: + case CSSPropertyWebkitGridRowGap: + validPrimitive = validateUnit(valueWithCalculation, FLength | FNonNeg); break; + case CSSPropertyWebkitGridGap: + return parseGridGapShorthand(important); + case CSSPropertyWebkitGridColumn: case CSSPropertyWebkitGridRow: { - if (!cssGridLayoutEnabled()) - return false; - return parseGridItemPositionShorthand(propId, important); } + case CSSPropertyWebkitGridTemplate: + return parseGridTemplateShorthand(important); + + case CSSPropertyWebkitGrid: + return parseGridShorthand(important); + + case CSSPropertyWebkitGridArea: + return parseGridAreaShorthand(important); + + case CSSPropertyWebkitGridTemplateAreas: + parsedValue = parseGridTemplateAreas(); + break; + case CSSPropertyWebkitGridAutoFlow: + parsedValue = parseGridAutoFlow(*m_valueList); + break; +#endif /* ENABLE(CSS_GRID_LAYOUT) */ case CSSPropertyWebkitMarginCollapse: { if (num == 1) { ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse); @@ -2698,109 +2856,115 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) id == CSSValueMedium || id == CSSValueThick) validPrimitive = true; else - validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent); + validPrimitive = !id && validateUnit(valueWithCalculation, FNumber | FLength | FPercent); break; - case CSSPropertyWebkitColumnCount: - if (id == CSSValueAuto) - validPrimitive = true; - else - validPrimitive = !id && validUnit(value, FPositiveInteger, CSSQuirksMode); + case CSSPropertyColumnCount: + parsedValue = parseColumnCount(); break; - case CSSPropertyWebkitColumnGap: // normal | <length> + case CSSPropertyColumnGap: // normal | <length> if (id == CSSValueNormal) validPrimitive = true; else - validPrimitive = validUnit(value, FLength | FNonNeg); + validPrimitive = validateUnit(valueWithCalculation, FLength | FNonNeg); break; case CSSPropertyWebkitColumnAxis: if (id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto) validPrimitive = true; break; - case CSSPropertyWebkitColumnProgression: + case CSSPropertyColumnProgression: if (id == CSSValueNormal || id == CSSValueReverse) validPrimitive = true; break; - case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property) + case CSSPropertyColumnSpan: // none | all | 1 (will be dropped in the unprefixed property) if (id == CSSValueAll || id == CSSValueNone) validPrimitive = true; - else - validPrimitive = validUnit(value, FNumber | FNonNeg) && value->fValue == 1; + else if (validateUnit(valueWithCalculation, FNumber | FNonNeg) && parsedDouble(valueWithCalculation) == 1) { + addProperty(CSSPropertyColumnSpan, cssValuePool.createValue(1, CSSPrimitiveValue::CSS_NUMBER), important); + return true; + } break; - case CSSPropertyWebkitColumnWidth: // auto | <length> + case CSSPropertyColumnWidth: // auto | <length> + parsedValue = parseColumnWidth(); + break; + // End of CSS3 properties + + case CSSPropertyWillChange: // auto | [scroll-position | contents | <custom-ident>]# if (id == CSSValueAuto) validPrimitive = true; - else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property. - validPrimitive = validUnit(value, FLength | FNonNeg, CSSStrictMode) && value->fValue; + else + return parseWillChange(important); break; - // End of CSS3 properties // Apple specific properties. These will never be standardized and are purely to // support custom WebKit-based Apple applications. case CSSPropertyWebkitLineClamp: // When specifying number of lines, don't allow 0 as a valid value // When specifying either type of unit, require non-negative integers - validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, CSSQuirksMode)); + validPrimitive = (!id && (valueWithCalculation.value().unit == CSSPrimitiveValue::CSS_PERCENTAGE || valueWithCalculation.value().fValue) && validateUnit(valueWithCalculation, FInteger | FPercent | FNonNeg, CSSQuirksMode)); break; - - case CSSPropertyWebkitFontSizeDelta: // <length> - validPrimitive = validUnit(value, FLength); +#if ENABLE(IOS_TEXT_AUTOSIZING) + case CSSPropertyWebkitTextSizeAdjust: + if (id == CSSValueAuto || id == CSSValueNone) + validPrimitive = true; + else { + // FIXME: Handle multilength case where we allow relative units. + validPrimitive = (!id && validateUnit(valueWithCalculation, FPercent | FNonNeg, CSSStrictMode)); + } break; +#endif - case CSSPropertyWebkitHighlight: - if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING) - validPrimitive = true; + case CSSPropertyWebkitFontSizeDelta: // <length> + validPrimitive = validateUnit(valueWithCalculation, FLength); break; case CSSPropertyWebkitHyphenateCharacter: - if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING) + if (id == CSSValueAuto || valueWithCalculation.value().unit == CSSPrimitiveValue::CSS_STRING) validPrimitive = true; break; case CSSPropertyWebkitHyphenateLimitBefore: case CSSPropertyWebkitHyphenateLimitAfter: - if (id == CSSValueAuto || validUnit(value, FInteger | FNonNeg, CSSStrictMode)) + if (id == CSSValueAuto || validateUnit(valueWithCalculation, FInteger | FNonNeg, CSSStrictMode)) validPrimitive = true; break; case CSSPropertyWebkitHyphenateLimitLines: - if (id == CSSValueNoLimit || validUnit(value, FInteger | FNonNeg, CSSStrictMode)) + if (id == CSSValueNoLimit || validateUnit(valueWithCalculation, FInteger | FNonNeg, CSSStrictMode)) validPrimitive = true; break; case CSSPropertyWebkitLineGrid: if (id == CSSValueNone) validPrimitive = true; - else if (value->unit == CSSPrimitiveValue::CSS_IDENT) { - String lineGridValue = String(value->string); + else if (valueWithCalculation.value().unit == CSSPrimitiveValue::CSS_IDENT) { + String lineGridValue = String(valueWithCalculation.value().string); if (!lineGridValue.isEmpty()) { - addProperty(propId, cssValuePool().createValue(lineGridValue, CSSPrimitiveValue::CSS_STRING), important); + addProperty(propId, cssValuePool.createValue(lineGridValue, CSSPrimitiveValue::CSS_STRING), important); return true; } } break; case CSSPropertyWebkitLocale: - if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING) + if (id == CSSValueAuto || valueWithCalculation.value().unit == CSSPrimitiveValue::CSS_STRING) validPrimitive = true; break; #if ENABLE(DASHBOARD_SUPPORT) case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region> - if (value->unit == CSSParserValue::Function || id == CSSValueNone) + if (valueWithCalculation.value().unit == CSSParserValue::Function || id == CSSValueNone) return parseDashboardRegions(propId, important); break; #endif - // End Apple-specific properties -#if ENABLE(DRAGGABLE_REGION) - case CSSPropertyWebkitAppRegion: - if (id >= CSSValueDrag && id <= CSSValueNoDrag) +#if PLATFORM(IOS) + case CSSPropertyWebkitTouchCallout: + if (id == CSSValueDefault || id == CSSValueNone) validPrimitive = true; break; #endif - #if ENABLE(TOUCH_EVENTS) case CSSPropertyWebkitTapHighlightColor: - if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu + if (isValidSystemColorValue(id) || id == CSSValueMenu || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) { validPrimitive = true; } else { @@ -2810,6 +2974,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) } break; #endif + // End Apple-specific properties /* shorthand properties */ case CSSPropertyBackground: { @@ -2821,7 +2986,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important); } case CSSPropertyWebkitMask: { - const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat, + const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskSourceType, CSSPropertyWebkitMaskRepeat, CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize }; return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important); } @@ -2831,7 +2996,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) if (parseShorthand(propId, borderAbridgedShorthand(), important)) { // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as // though a value of none was specified for the image. - addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important); + addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool.createImplicitInitialValue(), important); return true; } return false; @@ -2874,26 +3039,27 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyPadding: // <padding-width>{1,4} | inherit return parse4Values(propId, paddingShorthand().properties(), important); - case CSSPropertyWebkitFlexFlow: - return parseShorthand(propId, webkitFlexFlowShorthand(), important); + case CSSPropertyFlexFlow: + return parseShorthand(propId, flexFlowShorthand(), important); case CSSPropertyFont: // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit - if (id >= CSSValueCaption && id <= CSSValueStatusBar) - validPrimitive = true; - else - return parseFont(important); - break; + if (num == 1 && id >= CSSValueCaption && id <= CSSValueStatusBar) { + parseSystemFont(important); + return true; + } + return parseFont(important); case CSSPropertyListStyle: return parseShorthand(propId, listStyleShorthand(), important); - case CSSPropertyWebkitColumns: - return parseShorthand(propId, webkitColumnsShorthand(), important); - case CSSPropertyWebkitColumnRule: - return parseShorthand(propId, webkitColumnRuleShorthand(), important); + case CSSPropertyColumns: + return parseColumnsShorthand(important); + case CSSPropertyColumnRule: + return parseShorthand(propId, columnRuleShorthand(), important); case CSSPropertyWebkitTextStroke: return parseShorthand(propId, webkitTextStrokeShorthand(), important); + case CSSPropertyAnimation: case CSSPropertyWebkitAnimation: - return parseAnimationShorthand(important); + return parseAnimationShorthand(propId, important); case CSSPropertyTransition: case CSSPropertyWebkitTransition: return parseTransitionShorthand(propId, important); @@ -2901,10 +3067,6 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) return false; case CSSPropertyPage: return parsePage(propId, important); -#if ENABLE(CSS_SHADERS) - case CSSPropertyGeometry: - return m_inFilterRule ? parseGeometry(propId, value, important) : false; -#endif case CSSPropertyFontStretch: case CSSPropertyTextLineThrough: case CSSPropertyTextOverline: @@ -2917,68 +3079,81 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyWebkitTextEmphasisStyle: return parseTextEmphasisStyle(important); + case CSSPropertyWebkitTextEmphasisPosition: + return parseTextEmphasisPosition(important); + case CSSPropertyWebkitTextOrientation: - // FIXME: For now just support sideways, sideways-right, upright and vertical-right. - if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSValueVerticalRight || id == CSSValueUpright) + if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSValueVerticalRight || id == CSSValueMixed || id == CSSValueUpright) validPrimitive = true; break; + case CSSPropertyHangingPunctuation: + return parseHangingPunctuation(important); case CSSPropertyWebkitLineBoxContain: if (id == CSSValueNone) validPrimitive = true; else return parseLineBoxContain(important); break; - case CSSPropertyWebkitFontFeatureSettings: + case CSSPropertyFontFeatureSettings: if (id == CSSValueNormal) validPrimitive = true; else return parseFontFeatureSettings(important); break; - - case CSSPropertyWebkitFontVariantLigatures: + case CSSPropertyFontVariantLigatures: + if (id == CSSValueNormal || id == CSSValueNone) + validPrimitive = true; + else + return parseFontVariantLigatures(important, true, false); + break; + case CSSPropertyFontVariantNumeric: if (id == CSSValueNormal) validPrimitive = true; else - return parseFontVariantLigatures(important); + return parseFontVariantNumeric(important, true, false); break; - case CSSPropertyWebkitClipPath: - if (id == CSSValueNone) + case CSSPropertyFontVariantEastAsian: + if (id == CSSValueNormal) validPrimitive = true; - else if (value->unit == CSSParserValue::Function) - return parseBasicShape(propId, important); -#if ENABLE(SVG) - else if (value->unit == CSSPrimitiveValue::CSS_URI) { - parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI); - addProperty(propId, parsedValue.release(), important); + else + return parseFontVariantEastAsian(important, true, false); + break; + case CSSPropertyFontVariant: + if (id == CSSValueNormal) { + ShorthandScope scope(this, CSSPropertyFontVariant); + addProperty(CSSPropertyFontVariantLigatures, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important, true); + addProperty(CSSPropertyFontVariantPosition, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important, true); + addProperty(CSSPropertyFontVariantCaps, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important, true); + addProperty(CSSPropertyFontVariantNumeric, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important, true); + addProperty(CSSPropertyFontVariantAlternates, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important, true); + addProperty(CSSPropertyFontVariantEastAsian, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important, true); return true; } -#endif + if (id == CSSValueNone) { + ShorthandScope scope(this, CSSPropertyFontVariant); + addProperty(CSSPropertyFontVariantLigatures, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important, true); + return true; + } + return parseFontVariant(important); + + case CSSPropertyWebkitClipPath: + parsedValue = parseClipPath(); break; #if ENABLE(CSS_SHAPES) - case CSSPropertyWebkitShapeInside: case CSSPropertyWebkitShapeOutside: - if (!RuntimeEnabledFeatures::cssShapesEnabled()) - return false; - if (id == CSSValueAuto) - validPrimitive = true; - else if (propId == CSSPropertyWebkitShapeInside && id == CSSValueOutsideShape) - validPrimitive = true; - else if (value->unit == CSSParserValue::Function) - return parseBasicShape(propId, important); - else if (value->unit == CSSPrimitiveValue::CSS_URI) { - parsedValue = CSSImageValue::create(completeURL(value->string)); - m_valueList->next(); - } + parsedValue = parseShapeProperty(propId); break; case CSSPropertyWebkitShapeMargin: - case CSSPropertyWebkitShapePadding: - validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FLength | FNonNeg)); + validPrimitive = (RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled() && !id && validateUnit(valueWithCalculation, FLength | FPercent | FNonNeg)); + break; + case CSSPropertyWebkitShapeImageThreshold: + validPrimitive = (RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled() && !id && validateUnit(valueWithCalculation, FNumber)); break; #endif #if ENABLE(CSS_IMAGE_ORIENTATION) case CSSPropertyImageOrientation: - validPrimitive = !id && validUnit(value, FAngle); + validPrimitive = !id && validateUnit(valueWithCalculation, FAngle); break; #endif #if ENABLE(CSS_IMAGE_RESOLUTION) @@ -2986,12 +3161,23 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) parsedValue = parseImageResolution(); break; #endif + case CSSPropertyAlignContent: + parsedValue = parseContentDistributionOverflowPosition(); + break; + case CSSPropertyAlignSelf: + return parseItemPositionOverflowPosition(propId, important); + + case CSSPropertyAlignItems: + return parseItemPositionOverflowPosition(propId, important); case CSSPropertyBorderBottomStyle: case CSSPropertyBorderCollapse: case CSSPropertyBorderLeftStyle: case CSSPropertyBorderRightStyle: case CSSPropertyBorderTopStyle: case CSSPropertyBoxSizing: + case CSSPropertyBreakAfter: + case CSSPropertyBreakBefore: + case CSSPropertyBreakInside: case CSSPropertyCaptionSide: case CSSPropertyClear: case CSSPropertyDirection: @@ -3002,6 +3188,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyImageRendering: case CSSPropertyListStylePosition: case CSSPropertyListStyleType: + case CSSPropertyObjectFit: case CSSPropertyOutlineStyle: case CSSPropertyOverflowWrap: case CSSPropertyOverflowX: @@ -3023,9 +3210,6 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyTextTransform: case CSSPropertyTextUnderlineMode: case CSSPropertyTextUnderlineStyle: -#if ENABLE(CSS_VARIABLES) - case CSSPropertyVariable: -#endif case CSSPropertyVisibility: case CSSPropertyWebkitAppearance: case CSSPropertyWebkitBackfaceVisibility: @@ -3042,21 +3226,16 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyWebkitBoxLines: case CSSPropertyWebkitBoxOrient: case CSSPropertyWebkitBoxPack: - case CSSPropertyWebkitColorCorrection: case CSSPropertyWebkitColumnBreakAfter: case CSSPropertyWebkitColumnBreakBefore: case CSSPropertyWebkitColumnBreakInside: - case CSSPropertyWebkitColumnRuleStyle: - case CSSPropertyWebkitAlignContent: - case CSSPropertyWebkitAlignItems: - case CSSPropertyWebkitAlignSelf: - case CSSPropertyWebkitFlexDirection: - case CSSPropertyWebkitFlexWrap: - case CSSPropertyWebkitJustifyContent: + case CSSPropertyColumnFill: + case CSSPropertyColumnRuleStyle: + case CSSPropertyFlexDirection: + case CSSPropertyFlexWrap: case CSSPropertyWebkitFontKerning: case CSSPropertyWebkitFontSmoothing: case CSSPropertyWebkitHyphens: - case CSSPropertyWebkitGridAutoFlow: case CSSPropertyWebkitLineAlign: case CSSPropertyWebkitLineBreak: case CSSPropertyWebkitLineSnap: @@ -3083,23 +3262,28 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyWebkitTextAlignLast: #endif // CSS3_TEXT case CSSPropertyWebkitTextCombine: - case CSSPropertyWebkitTextEmphasisPosition: #if ENABLE(CSS3_TEXT) case CSSPropertyWebkitTextJustify: #endif // CSS3_TEXT case CSSPropertyWebkitTextSecurity: + case CSSPropertyTransformStyle: case CSSPropertyWebkitTransformStyle: case CSSPropertyWebkitUserDrag: case CSSPropertyWebkitUserModify: case CSSPropertyWebkitUserSelect: -#if ENABLE(CSS_EXCLUSIONS) - case CSSPropertyWebkitWrapFlow: - case CSSPropertyWebkitWrapThrough: -#endif case CSSPropertyWebkitWritingMode: case CSSPropertyWhiteSpace: case CSSPropertyWordBreak: case CSSPropertyWordWrap: +#if ENABLE(TOUCH_EVENTS) + case CSSPropertyTouchAction: +#endif +#if ENABLE(CSS_SCROLL_SNAP) + case CSSPropertyWebkitScrollSnapType: +#endif +#if ENABLE(CSS_TRAILING_WORD) + case CSSPropertyAppleTrailingWord: +#endif // These properties should be handled before in isValidKeywordPropertyAndValue(). ASSERT_NOT_REACHED(); return false; @@ -3114,17 +3298,29 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) validPrimitive = false; break; #endif -#if ENABLE(SVG) +#if ENABLE(CSS_SCROLL_SNAP) + case CSSPropertyWebkitScrollSnapPointsX: + case CSSPropertyWebkitScrollSnapPointsY: + if (id == CSSValueElements) { + validPrimitive = true; + break; + } + return parseNonElementSnapPoints(propId, important); + case CSSPropertyWebkitScrollSnapDestination: // <length>{2} + return parseScrollSnapDestination(propId, important); + case CSSPropertyWebkitScrollSnapCoordinate: + return parseScrollSnapCoordinate(propId, important); +#endif + default: return parseSVGValue(propId, important); -#endif } if (validPrimitive) { - parsedValue = parseValidPrimitive(id, value); + parsedValue = parseValidPrimitive(id, valueWithCalculation); m_valueList->next(); } - ASSERT(!m_parsedCalculation); + if (parsedValue) { if (!m_valueList->current() || inShorthand()) { addProperty(propId, parsedValue.release(), important); @@ -3134,28 +3330,186 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) return false; } -void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval) +void CSSParser::addFillValue(RefPtr<CSSValue>& lval, Ref<CSSValue>&& rval) { - if (lval) { - if (lval->isBaseValueList()) - static_cast<CSSValueList*>(lval.get())->append(rval); - else { - PassRefPtr<CSSValue> oldlVal(lval.release()); - PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); - list->append(oldlVal); - list->append(rval); - lval = list; - } + if (!lval) { + lval = WTFMove(rval); + return; } + + if (lval->isBaseValueList()) { + downcast<CSSValueList>(*lval).append(WTFMove(rval)); + return; + } + + auto list = CSSValueList::createCommaSeparated(); + list.get().append(lval.releaseNonNull()); + list.get().append(WTFMove(rval)); + lval = WTFMove(list); +} + +static bool isContentDistributionKeyword(CSSValueID id) +{ + return id == CSSValueSpaceBetween || id == CSSValueSpaceAround + || id == CSSValueSpaceEvenly || id == CSSValueStretch; +} + +static bool isContentPositionKeyword(CSSValueID id) +{ + return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter + || id == CSSValueFlexStart || id == CSSValueFlexEnd + || id == CSSValueLeft || id == CSSValueRight; +} + +static inline bool isBaselinePositionKeyword(CSSValueID id) +{ + return id == CSSValueBaseline || id == CSSValueLastBaseline; +} + +static bool isAlignmentOverflowKeyword(CSSValueID id) +{ + return id == CSSValueUnsafe || id == CSSValueSafe; +} + +static bool isItemPositionKeyword(CSSValueID id) +{ + return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter + || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart + || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight; +} + +bool CSSParser::parseLegacyPosition(CSSPropertyID propId, bool important) +{ + // [ legacy && [ left | right | center ] + + CSSParserValue* value = m_valueList->current(); + if (!value) + return false; + + if (value->id == CSSValueLegacy) { + value = m_valueList->next(); + if (!value) + return false; + if (value->id != CSSValueCenter && value->id != CSSValueLeft && value->id != CSSValueRight) + return false; + } else if (value->id == CSSValueCenter || value->id == CSSValueLeft || value->id == CSSValueRight) { + if (!m_valueList->next() || m_valueList->current()->id != CSSValueLegacy) + return false; + } else + return false; + + auto& cssValuePool = CSSValuePool::singleton(); + addProperty(propId, createPrimitiveValuePair(cssValuePool.createIdentifierValue(CSSValueLegacy), cssValuePool.createIdentifierValue(value->id)), important); + return !m_valueList->next(); +} + +RefPtr<CSSValue> CSSParser::parseContentDistributionOverflowPosition() +{ + // auto | <baseline-position> | <content-distribution> || [ <overflow-position>? && <content-position> ] + // <baseline-position> = baseline | last-baseline; + // <content-distribution> = space-between | space-around | space-evenly | stretch; + // <content-position> = center | start | end | flex-start | flex-end | left | right; + // <overflow-position> = true | safe + + CSSParserValue* value = m_valueList->current(); + if (!value) + return nullptr; + + // auto | <baseline-position> + if (value->id == CSSValueAuto || isBaselinePositionKeyword(value->id)) { + m_valueList->next(); + return CSSContentDistributionValue::create(CSSValueInvalid, value->id, CSSValueInvalid); + } + + CSSValueID distribution = CSSValueInvalid; + CSSValueID position = CSSValueInvalid; + CSSValueID overflow = CSSValueInvalid; + while (value) { + if (isContentDistributionKeyword(value->id)) { + if (distribution != CSSValueInvalid) + return nullptr; + distribution = value->id; + } else if (isContentPositionKeyword(value->id)) { + if (position != CSSValueInvalid) + return nullptr; + position = value->id; + } else if (isAlignmentOverflowKeyword(value->id)) { + if (overflow != CSSValueInvalid) + return nullptr; + overflow = value->id; + } else + return nullptr; + value = m_valueList->next(); + } + + // The grammar states that we should have at least <content-distribution> or + // <content-position> ( <content-distribution> || <content-position> ). + if (position == CSSValueInvalid && distribution == CSSValueInvalid) + return nullptr; + + // The grammar states that <overflow-position> must be associated to <content-position>. + if (overflow != CSSValueInvalid && position == CSSValueInvalid) + return nullptr; + + return CSSContentDistributionValue::create(distribution, position, overflow); +} + +bool CSSParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important) +{ + // auto | stretch | <baseline-position> | [<item-position> && <overflow-position>? ] + // <baseline-position> = baseline | last-baseline; + // <item-position> = center | start | end | self-start | self-end | flex-start | flex-end | left | right; + // <overflow-position> = true | safe + + CSSParserValue* value = m_valueList->current(); + if (!value) + return false; + + if (value->id == CSSValueAuto || value->id == CSSValueStretch || isBaselinePositionKeyword(value->id)) { + if (m_valueList->next()) + return false; + + addProperty(propId, CSSValuePool::singleton().createIdentifierValue(value->id), important); + return true; + } + + RefPtr<CSSPrimitiveValue> position; + RefPtr<CSSPrimitiveValue> overflowAlignmentKeyword; + if (isItemPositionKeyword(value->id)) { + position = CSSValuePool::singleton().createIdentifierValue(value->id); + value = m_valueList->next(); + if (value) { + if (value->id != CSSValueUnsafe && value->id != CSSValueSafe) + return false; + overflowAlignmentKeyword = CSSValuePool::singleton().createIdentifierValue(value->id); + } + } else if (isAlignmentOverflowKeyword(value->id)) { + overflowAlignmentKeyword = CSSValuePool::singleton().createIdentifierValue(value->id); + value = m_valueList->next(); + if (value && isItemPositionKeyword(value->id)) + position = CSSValuePool::singleton().createIdentifierValue(value->id); + else + return false; + } else + return false; + + if (m_valueList->next()) + return false; + + ASSERT(position); + if (overflowAlignmentKeyword) + addProperty(propId, createPrimitiveValuePair(position.release(), overflowAlignmentKeyword.release()), important); else - lval = rval; + addProperty(propId, position.release(), important); + + return true; } -static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue) +static bool parseBackgroundClip(CSSParserValue& parserValue, RefPtr<CSSValue>& cssValue) { - if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox - || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) { - cssValue = cssValuePool().createIdentifierValue(parserValue->id); + if (parserValue.id == CSSValueBorderBox || parserValue.id == CSSValuePaddingBox + || parserValue.id == CSSValueContentBox || parserValue.id == CSSValueWebkitText) { + cssValue = CSSValuePool::singleton().createIdentifierValue(parserValue.id); return true; } return false; @@ -3166,6 +3520,93 @@ bool CSSParser::useLegacyBackgroundSizeShorthandBehavior() const return m_context.useLegacyBackgroundSizeShorthandBehavior; } +#if ENABLE(CSS_SCROLL_SNAP) +bool CSSParser::parseNonElementSnapPoints(CSSPropertyID propId, bool important) +{ + RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated(); + while (CSSParserValue* value = m_valueList->current()) { + ValueWithCalculation valueWithCalculation(*value); + if (validateUnit(valueWithCalculation, FPercent | FLength)) + values->append(createPrimitiveNumericValue(valueWithCalculation)); + else if (value->unit == CSSParserValue::Function + && value->function->args + && value->function->args->size() == 1 + && equalLettersIgnoringASCIICase(value->function->name, "repeat(")) { + ValueWithCalculation argumentWithCalculation(*value->function->args.get()->current()); + if (validateUnit(argumentWithCalculation, FLength | FPercent | FNonNeg)) { + values->append(CSSValuePool::singleton().createValue(LengthRepeat::create(createPrimitiveNumericValue(argumentWithCalculation)))); + m_valueList->next(); + if (m_valueList->current()) + return false; + break; + } + } else + return false; + m_valueList->next(); + } + if (values->length()) { + addProperty(propId, values.release(), important); + m_valueList->next(); + return true; + } + return false; +} + +bool CSSParser::parseScrollSnapPositions(RefPtr<CSSValue>& cssValueX, RefPtr<CSSValue>& cssValueY) +{ + cssValueX = parsePositionX(*m_valueList); + if (!cssValueX) + return false; + + // Don't accept odd-length lists of positions (must always have an X and a Y): + if (!m_valueList->next()) + return false; + + cssValueY = parsePositionY(*m_valueList); + if (!cssValueY) + return false; + + return true; +} + +bool CSSParser::parseScrollSnapDestination(CSSPropertyID propId, bool important) +{ + RefPtr<CSSValueList> position = CSSValueList::createSpaceSeparated(); + if (m_valueList->size() != 2) + return false; + + RefPtr<CSSValue> cssValueX, cssValueY; + if (!parseScrollSnapPositions(cssValueX, cssValueY)) + return false; + + position->append(cssValueX.releaseNonNull()); + position->append(cssValueY.releaseNonNull()); + addProperty(propId, position, important); + m_valueList->next(); + return true; +} + +bool CSSParser::parseScrollSnapCoordinate(CSSPropertyID propId, bool important) +{ + RefPtr<CSSValueList> positions = CSSValueList::createSpaceSeparated(); + while (m_valueList->current()) { + RefPtr<CSSValue> cssValueX, cssValueY; + if (!parseScrollSnapPositions(cssValueX, cssValueY)) + return false; + + positions->append(cssValueX.releaseNonNull()); + positions->append(cssValueY.releaseNonNull()); + m_valueList->next(); + } + + if (positions->length()) { + addProperty(propId, positions.release(), important); + return true; + } + return false; +} +#endif + const int cMaxFillProperties = 9; bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important) @@ -3185,9 +3626,10 @@ bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* pr int i; bool foundPositionCSSProperty = false; + auto& cssValuePool = CSSValuePool::singleton(); while (m_valueList->current()) { - CSSParserValue* val = m_valueList->current(); - if (val->unit == CSSParserValue::Operator && val->iValue == ',') { + CSSParserValue& currentValue = *m_valueList->current(); + if (currentValue.unit == CSSParserValue::Operator && currentValue.iValue == ',') { // We hit the end. Fill in all remaining values with the initial value. m_valueList->next(); for (i = 0; i < numProperties; ++i) { @@ -3197,14 +3639,14 @@ bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* pr return false; if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) { - addFillValue(values[i], cssValuePool().createImplicitInitialValue()); + addFillValue(values[i], cssValuePool.createImplicitInitialValue()); if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) - addFillValue(positionYValue, cssValuePool().createImplicitInitialValue()); + addFillValue(positionYValue, cssValuePool.createImplicitInitialValue()); if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) - addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue()); + addFillValue(repeatYValue, cssValuePool.createImplicitInitialValue()); if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) { // If background-origin wasn't present, then reset background-clip also. - addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); + addFillValue(clipValue, cssValuePool.createImplicitInitialValue()); } } parsedProperty[i] = false; @@ -3214,7 +3656,7 @@ bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* pr } bool sizeCSSPropertyExpected = false; - if (isForwardSlashOperator(val) && foundPositionCSSProperty) { + if (isForwardSlashOperator(currentValue) && foundPositionCSSProperty) { sizeCSSPropertyExpected = true; m_valueList->next(); } @@ -3232,26 +3674,24 @@ bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* pr RefPtr<CSSValue> val1; RefPtr<CSSValue> val2; CSSPropertyID propId1, propId2; - CSSParserValue* parserValue = m_valueList->current(); + CSSParserValue& parserValue = *m_valueList->current(); + if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) { parsedProperty[i] = found = true; - addFillValue(values[i], val1.release()); + addFillValue(values[i], val1.releaseNonNull()); if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) - addFillValue(positionYValue, val2.release()); + addFillValue(positionYValue, val2.releaseNonNull()); if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) - addFillValue(repeatYValue, val2.release()); + addFillValue(repeatYValue, val2.releaseNonNull()); if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) { // Reparse the value as a clip, and see if we succeed. if (parseBackgroundClip(parserValue, val1)) - addFillValue(clipValue, val1.release()); // The property parsed successfully. + addFillValue(clipValue, val1.releaseNonNull()); // The property parsed successfully. else - addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead. + addFillValue(clipValue, cssValuePool.createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead. } - if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) { - // Update clipValue - addFillValue(clipValue, val1.release()); + if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) foundClip = true; - } if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) foundPositionCSSProperty = true; } @@ -3265,17 +3705,17 @@ bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* pr } // Now add all of the properties we found. - for (i = 0; i < numProperties; i++) { + for (i = 0; i < numProperties; ++i) { // Fill in any remaining properties with the initial value. if (!parsedProperty[i]) { - addFillValue(values[i], cssValuePool().createImplicitInitialValue()); + addFillValue(values[i], cssValuePool.createImplicitInitialValue()); if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) - addFillValue(positionYValue, cssValuePool().createImplicitInitialValue()); + addFillValue(positionYValue, cssValuePool.createImplicitInitialValue()); if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) - addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue()); + addFillValue(repeatYValue, cssValuePool.createImplicitInitialValue()); if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) { // If background-origin wasn't present, then reset background-clip also. - addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); + addFillValue(clipValue, cssValuePool.createImplicitInitialValue()); } } if (properties[i] == CSSPropertyBackgroundPosition) { @@ -3312,70 +3752,45 @@ bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* pr return true; } -#if ENABLE(CSS_VARIABLES) -bool CSSParser::cssVariablesEnabled() const +void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, Ref<CSSValue>&& rval) { - return m_context.isCSSVariablesEnabled; -} - -void CSSParser::storeVariableDeclaration(const CSSParserString& name, PassOwnPtr<CSSParserValueList> value, bool important) -{ - // When CSSGrammar.y encounters an invalid declaration it passes null for the CSSParserValueList, just bail. - if (!value) + if (!lval) { + lval = WTFMove(rval); return; - - static const unsigned prefixLength = sizeof("-webkit-var-") - 1; - - ASSERT(name.length() > prefixLength); - AtomicString variableName = name.substring(prefixLength, name.length() - prefixLength); - - StringBuilder builder; - for (unsigned i = 0, size = value->size(); i < size; i++) { - if (i) - builder.append(' '); - RefPtr<CSSValue> cssValue = value->valueAt(i)->createCSSValue(); - if (!cssValue) - return; - builder.append(cssValue->cssText()); } - addProperty(CSSPropertyVariable, CSSVariableValue::create(variableName, builder.toString().lower()), important, false); -} -#endif -void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval) -{ - if (lval) { - if (lval->isValueList()) - static_cast<CSSValueList*>(lval.get())->append(rval); - else { - PassRefPtr<CSSValue> oldVal(lval.release()); - PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); - list->append(oldVal); - list->append(rval); - lval = list; - } + if (is<CSSValueList>(*lval)) { + downcast<CSSValueList>(*lval).append(WTFMove(rval)); + return; } - else - lval = rval; + + auto list = CSSValueList::createCommaSeparated(); + list.get().append(lval.releaseNonNull()); + list.get().append(WTFMove(rval)); + lval = WTFMove(list); } -bool CSSParser::parseAnimationShorthand(bool important) +bool CSSParser::parseAnimationShorthand(CSSPropertyID propId, bool important) { - const StylePropertyShorthand& animationProperties = webkitAnimationShorthandForParsing(); - const unsigned numProperties = 7; + ASSERT(propId == CSSPropertyAnimation || propId == CSSPropertyWebkitAnimation); + + const unsigned numProperties = 8; + const StylePropertyShorthand& shorthand = animationShorthandForParsing(propId); // The list of properties in the shorthand should be the same // length as the list with animation name in last position, even though they are // in a different order. - ASSERT(numProperties == webkitAnimationShorthandForParsing().length()); + ASSERT(numProperties == shorthand.length()); + ASSERT(numProperties == animationShorthand().length()); ASSERT(numProperties == webkitAnimationShorthand().length()); - ShorthandScope scope(this, CSSPropertyWebkitAnimation); + ShorthandScope scope(this, propId); bool parsedProperty[numProperties] = { false }; AnimationParseContext context; RefPtr<CSSValue> values[numProperties]; + auto& cssValuePool = CSSValuePool::singleton(); unsigned i; while (m_valueList->current()) { CSSParserValue* val = m_valueList->current(); @@ -3384,7 +3799,7 @@ bool CSSParser::parseAnimationShorthand(bool important) m_valueList->next(); for (i = 0; i < numProperties; ++i) { if (!parsedProperty[i]) - addAnimationValue(values[i], cssValuePool().createImplicitInitialValue()); + addAnimationValue(values[i], cssValuePool.createImplicitInitialValue()); parsedProperty[i] = false; } if (!m_valueList->current()) @@ -3396,9 +3811,9 @@ bool CSSParser::parseAnimationShorthand(bool important) for (i = 0; i < numProperties; ++i) { if (!parsedProperty[i]) { RefPtr<CSSValue> val; - if (parseAnimationProperty(animationProperties.properties()[i], val, context)) { + if (parseAnimationProperty(shorthand.properties()[i], val, context)) { parsedProperty[i] = found = true; - addAnimationValue(values[i], val.release()); + addAnimationValue(values[i], val.releaseNonNull()); break; } } @@ -3417,14 +3832,84 @@ bool CSSParser::parseAnimationShorthand(bool important) for (i = 0; i < numProperties; ++i) { // If we didn't find the property, set an intial value. if (!parsedProperty[i]) - addAnimationValue(values[i], cssValuePool().createImplicitInitialValue()); + addAnimationValue(values[i], cssValuePool.createImplicitInitialValue()); - addProperty(animationProperties.properties()[i], values[i].release(), important); + addProperty(shorthand.properties()[i], values[i].release(), important); } return true; } +RefPtr<CSSValue> CSSParser::parseColumnWidth() +{ + ValueWithCalculation valueWithCalculation(*m_valueList->current()); + CSSValueID id = valueWithCalculation.value().id; + // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property. + if (id != CSSValueAuto && !(validateUnit(valueWithCalculation, FLength | FNonNeg, CSSStrictMode) && parsedDouble(valueWithCalculation))) + return nullptr; + + RefPtr<CSSValue> parsedValue = parseValidPrimitive(id, valueWithCalculation); + m_valueList->next(); + return parsedValue; +} + +RefPtr<CSSValue> CSSParser::parseColumnCount() +{ + ValueWithCalculation valueWithCalculation(*m_valueList->current()); + CSSValueID id = valueWithCalculation.value().id; + + if (id != CSSValueAuto && !validateUnit(valueWithCalculation, FPositiveInteger, CSSQuirksMode)) + return nullptr; + + RefPtr<CSSValue> parsedValue = parseValidPrimitive(id, valueWithCalculation); + m_valueList->next(); + return parsedValue; +} + +bool CSSParser::parseColumnsShorthand(bool important) +{ + RefPtr<CSSValue> columnWidth; + RefPtr<CSSValue> columnCount; + bool hasPendingExplicitAuto = false; + + for (unsigned propertiesParsed = 0; CSSParserValue* value = m_valueList->current(); propertiesParsed++) { + if (propertiesParsed >= 2) + return false; // Too many values for this shorthand. Invalid declaration. + if (!propertiesParsed && value->id == CSSValueAuto) { + // 'auto' is a valid value for any of the two longhands, and at this point + // we don't know which one(s) it is meant for. We need to see if there are other values first. + m_valueList->next(); + hasPendingExplicitAuto = true; + } else { + if (!columnWidth) { + if ((columnWidth = parseColumnWidth())) + continue; + } + if (!columnCount) { + if ((columnCount = parseColumnCount())) + continue; + } + // If we didn't find at least one match, this is an invalid shorthand and we have to ignore it. + return false; + } + } + + // Any unassigned property at this point will become implicit 'auto'. + if (columnWidth) + addProperty(CSSPropertyColumnWidth, columnWidth, important); + else { + addProperty(CSSPropertyColumnWidth, CSSValuePool::singleton().createIdentifierValue(CSSValueAuto), important, !hasPendingExplicitAuto /* implicit */); + hasPendingExplicitAuto = false; + } + + if (columnCount) + addProperty(CSSPropertyColumnCount, columnCount, important); + else + addProperty(CSSPropertyColumnCount, CSSValuePool::singleton().createIdentifierValue(CSSValueAuto), important, !hasPendingExplicitAuto /* implicit */); + + return true; +} + bool CSSParser::parseTransitionShorthand(CSSPropertyID propId, bool important) { const unsigned numProperties = 4; @@ -3437,6 +3922,7 @@ bool CSSParser::parseTransitionShorthand(CSSPropertyID propId, bool important) AnimationParseContext context; RefPtr<CSSValue> values[numProperties]; + auto& cssValuePool = CSSValuePool::singleton(); unsigned i; while (m_valueList->current()) { CSSParserValue* val = m_valueList->current(); @@ -3445,7 +3931,7 @@ bool CSSParser::parseTransitionShorthand(CSSPropertyID propId, bool important) m_valueList->next(); for (i = 0; i < numProperties; ++i) { if (!parsedProperty[i]) - addAnimationValue(values[i], cssValuePool().createImplicitInitialValue()); + addAnimationValue(values[i], cssValuePool.createImplicitInitialValue()); parsedProperty[i] = false; } if (!m_valueList->current()) @@ -3459,7 +3945,7 @@ bool CSSParser::parseTransitionShorthand(CSSPropertyID propId, bool important) RefPtr<CSSValue> val; if (parseAnimationProperty(shorthand.properties()[i], val, context)) { parsedProperty[i] = found = true; - addAnimationValue(values[i], val.release()); + addAnimationValue(values[i], val.releaseNonNull()); } // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid. @@ -3477,11 +3963,11 @@ bool CSSParser::parseTransitionShorthand(CSSPropertyID propId, bool important) // Fill in any remaining properties with the initial value. for (i = 0; i < numProperties; ++i) { if (!parsedProperty[i]) - addAnimationValue(values[i], cssValuePool().createImplicitInitialValue()); + addAnimationValue(values[i], cssValuePool.createImplicitInitialValue()); } // Now add all of the properties we found. - for (i = 0; i < numProperties; i++) + for (i = 0; i < numProperties; ++i) addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].release(), important); return true; @@ -3517,18 +4003,19 @@ bool CSSParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthan return true; // Fill in any remaining properties with the initial value. - ImplicitScope implicitScope(this, PropertyImplicit); - const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization(); + auto& cssValuePool = CSSValuePool::singleton(); + ImplicitScope implicitScope(*this, PropertyImplicit); + const StylePropertyShorthand* propertiesForInitialization = shorthand.propertiesForInitialization(); for (unsigned i = 0; i < shorthand.length(); ++i) { if (propertyFound[i]) continue; if (propertiesForInitialization) { - const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]); + const StylePropertyShorthand& initProperties = propertiesForInitialization[i]; for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex) - addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important); + addProperty(initProperties.properties()[propIndex], cssValuePool.createImplicitInitialValue(), important); } else - addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important); + addProperty(shorthand.properties()[i], cssValuePool.createImplicitInitialValue(), important); } return true; @@ -3544,7 +4031,7 @@ bool CSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properti * right, bottom, and left, respectively. */ - int num = inShorthand() ? 1 : m_valueList->size(); + unsigned num = inShorthand() ? 1 : m_valueList->size(); ShorthandScope scope(this, propId); @@ -3554,7 +4041,7 @@ bool CSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properti if (!parseValue(properties[0], important)) return false; CSSValue* value = m_parsedProperties.last().value(); - ImplicitScope implicitScope(this, PropertyImplicit); + ImplicitScope implicitScope(*this, PropertyImplicit); addProperty(properties[1], value, important); addProperty(properties[2], value, important); addProperty(properties[3], value, important); @@ -3564,7 +4051,7 @@ bool CSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properti if (!parseValue(properties[0], important) || !parseValue(properties[1], important)) return false; CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value(); - ImplicitScope implicitScope(this, PropertyImplicit); + ImplicitScope implicitScope(*this, PropertyImplicit); addProperty(properties[2], value, important); value = m_parsedProperties[m_parsedProperties.size() - 2].value(); addProperty(properties[3], value, important); @@ -3574,7 +4061,7 @@ bool CSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properti if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important)) return false; CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value(); - ImplicitScope implicitScope(this, PropertyImplicit); + ImplicitScope implicitScope(*this, PropertyImplicit); addProperty(properties[3], value, important); break; } @@ -3605,10 +4092,10 @@ bool CSSParser::parsePage(CSSPropertyID propId, bool important) return false; if (value->id == CSSValueAuto) { - addProperty(propId, cssValuePool().createIdentifierValue(value->id), important); + addProperty(propId, CSSValuePool::singleton().createIdentifierValue(value->id), important); return true; } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) { - addProperty(propId, createPrimitiveStringValue(value), important); + addProperty(propId, createPrimitiveStringValue(*value), important); return true; } return false; @@ -3629,14 +4116,14 @@ bool CSSParser::parseSize(CSSPropertyID propId, bool important) RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated(); // First parameter. - SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None); + SizeParameterType paramType = parseSizeParameter(*parsedValues, *value, None); if (paramType == None) return false; // Second parameter, if any. value = m_valueList->next(); if (value) { - paramType = parseSizeParameter(parsedValues.get(), value, paramType); + paramType = parseSizeParameter(*parsedValues, *value, paramType); if (paramType == None) return false; } @@ -3645,19 +4132,19 @@ bool CSSParser::parseSize(CSSPropertyID propId, bool important) return true; } -CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType) +CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList& parsedValues, CSSParserValue& value, SizeParameterType prevParamType) { - switch (value->id) { + switch (value.id) { case CSSValueAuto: if (prevParamType == None) { - parsedValues->append(cssValuePool().createIdentifierValue(value->id)); + parsedValues.append(CSSValuePool::singleton().createIdentifierValue(value.id)); return Auto; } return None; case CSSValueLandscape: case CSSValuePortrait: if (prevParamType == None || prevParamType == PageSize) { - parsedValues->append(cssValuePool().createIdentifierValue(value->id)); + parsedValues.append(CSSValuePool::singleton().createIdentifierValue(value.id)); return Orientation; } return None; @@ -3672,16 +4159,18 @@ CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedV if (prevParamType == None || prevParamType == Orientation) { // Normalize to Page Size then Orientation order by prepending. // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty). - parsedValues->prepend(cssValuePool().createIdentifierValue(value->id)); + parsedValues.prepend(CSSValuePool::singleton().createIdentifierValue(value.id)); return PageSize; } return None; - case 0: - if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) { - parsedValues->append(createPrimitiveNumericValue(value)); + case CSSValueInvalid: { + ValueWithCalculation valueWithCalculation(value); + if (validateUnit(valueWithCalculation, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) { + parsedValues.append(createPrimitiveNumericValue(valueWithCalculation)); return Length; } return None; + } default: return None; } @@ -3692,13 +4181,10 @@ CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedV bool CSSParser::parseQuotes(CSSPropertyID propId, bool important) { RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated(); - while (CSSParserValue* val = m_valueList->current()) { - RefPtr<CSSValue> parsedValue; - if (val->unit == CSSPrimitiveValue::CSS_STRING) - parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING); - else + while (CSSParserValue* value = m_valueList->current()) { + if (value->unit != CSSPrimitiveValue::CSS_STRING) break; - values->append(parsedValue.release()); + values->append(CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_STRING)); m_valueList->next(); } if (values->length()) { @@ -3709,6 +4195,57 @@ bool CSSParser::parseQuotes(CSSPropertyID propId, bool important) return false; } +bool CSSParser::parseAlt(CSSPropertyID propID, bool important) +{ + CSSParserValue& currentValue = *m_valueList->current(); + RefPtr<CSSValue> parsedValue; + + if (currentValue.unit == CSSPrimitiveValue::CSS_STRING) + parsedValue = createPrimitiveStringValue(currentValue); + else if (currentValue.unit == CSSParserValue::Function) { + CSSParserValueList* args = currentValue.function->args.get(); + if (!args) + return false; + if (equalLettersIgnoringASCIICase(currentValue.function->name, "attr(")) + parsedValue = parseAttr(*args); + } + + if (parsedValue) { + addProperty(propID, parsedValue.release(), important); + m_valueList->next(); + return true; + } + + return false; +} + +bool CSSParser::parseCustomPropertyDeclaration(bool important, CSSValueID id) +{ + if (m_customPropertyName.isEmpty() || !m_valueList) + return false; + + auto& cssValuePool = CSSValuePool::singleton(); + RefPtr<CSSValue> value; + if (id == CSSValueInherit) + value = cssValuePool.createInheritedValue(); + else if (id == CSSValueInitial) + value = cssValuePool.createExplicitInitialValue(); + else if (id == CSSValueUnset) + value = cssValuePool.createUnsetValue(); + else if (id == CSSValueRevert) + value = cssValuePool.createRevertValue(); + else { + RefPtr<CSSValueList> valueList = CSSValueList::createFromParserValueList(*m_valueList); + if (m_valueList->containsVariables()) + value = CSSVariableDependentValue::create(valueList, CSSPropertyCustom); + else + value = valueList; + } + + addProperty(CSSPropertyCustom, CSSCustomPropertyValue::create(m_customPropertyName, value), important, false); + return true; +} + // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit // in CSS 2.1 this got somewhat reduced: // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit @@ -3716,40 +4253,40 @@ bool CSSParser::parseContent(CSSPropertyID propId, bool important) { RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated(); - while (CSSParserValue* val = m_valueList->current()) { + while (CSSParserValue* value = m_valueList->current()) { RefPtr<CSSValue> parsedValue; - if (val->unit == CSSPrimitiveValue::CSS_URI) { + if (value->unit == CSSPrimitiveValue::CSS_URI) { // url - parsedValue = CSSImageValue::create(completeURL(val->string)); - } else if (val->unit == CSSParserValue::Function) { + parsedValue = CSSImageValue::create(completeURL(value->string)); + } else if (value->unit == CSSParserValue::Function) { // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...) - CSSParserValueList* args = val->function->args.get(); + CSSParserValueList* args = value->function->args.get(); if (!args) return false; - if (equalIgnoringCase(val->function->name, "attr(")) { - parsedValue = parseAttr(args); + if (equalLettersIgnoringASCIICase(value->function->name, "attr(")) { + parsedValue = parseAttr(*args); if (!parsedValue) return false; - } else if (equalIgnoringCase(val->function->name, "counter(")) { - parsedValue = parseCounterContent(args, false); + } else if (equalLettersIgnoringASCIICase(value->function->name, "counter(")) { + parsedValue = parseCounterContent(*args, false); if (!parsedValue) return false; - } else if (equalIgnoringCase(val->function->name, "counters(")) { - parsedValue = parseCounterContent(args, true); + } else if (equalLettersIgnoringASCIICase(value->function->name, "counters(")) { + parsedValue = parseCounterContent(*args, true); if (!parsedValue) return false; #if ENABLE(CSS_IMAGE_SET) - } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) { + } else if (equalLettersIgnoringASCIICase(value->function->name, "-webkit-image-set(")) { parsedValue = parseImageSet(); if (!parsedValue) return false; #endif - } else if (isGeneratedImageValue(val)) { - if (!parseGeneratedImage(m_valueList.get(), parsedValue)) + } else if (isGeneratedImageValue(*value)) { + if (!parseGeneratedImage(*m_valueList, parsedValue)) return false; } else return false; - } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) { + } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) { // open-quote // close-quote // no-open-quote @@ -3758,23 +4295,24 @@ bool CSSParser::parseContent(CSSPropertyID propId, bool important) // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503). // none // normal - switch (val->id) { + switch (value->id) { case CSSValueOpenQuote: case CSSValueCloseQuote: case CSSValueNoOpenQuote: case CSSValueNoCloseQuote: case CSSValueNone: case CSSValueNormal: - parsedValue = cssValuePool().createIdentifierValue(val->id); + parsedValue = CSSValuePool::singleton().createIdentifierValue(value->id); + break; default: break; } - } else if (val->unit == CSSPrimitiveValue::CSS_STRING) { - parsedValue = createPrimitiveStringValue(val); + } else if (value->unit == CSSPrimitiveValue::CSS_STRING) { + parsedValue = createPrimitiveStringValue(*value); } if (!parsedValue) break; - values->append(parsedValue.release()); + values->append(parsedValue.releaseNonNull()); m_valueList->next(); } @@ -3787,54 +4325,56 @@ bool CSSParser::parseContent(CSSPropertyID propId, bool important) return false; } -PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args) +RefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList& args) { - if (args->size() != 1) - return 0; + if (args.size() != 1) + return nullptr; - CSSParserValue* a = args->current(); + CSSParserValue& argument = *args.current(); - if (a->unit != CSSPrimitiveValue::CSS_IDENT) - return 0; + if (argument.unit != CSSPrimitiveValue::CSS_IDENT) + return nullptr; + + ASSERT(argument.string.length()); - String attrName = a->string; // CSS allows identifiers with "-" at the start, like "-webkit-mask-image". // But HTML attribute names can't have those characters, and we should not // even parse them inside attr(). - if (attrName[0] == '-') - return 0; + if (argument.string[0] == '-') + return nullptr; if (m_context.isHTMLDocument) - attrName = attrName.lower(); + argument.string.convertToASCIILowercaseInPlace(); - return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR); + // FIXME: Is there some small benefit to creating an AtomicString here instead of a String? + return CSSValuePool::singleton().createValue(String(argument.string), CSSPrimitiveValue::CSS_ATTR); } -PassRefPtr<CSSValue> CSSParser::parseBackgroundColor() +RefPtr<CSSValue> CSSParser::parseBackgroundColor() { CSSValueID id = m_valueList->current()->id; - if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor || - (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode())) - return cssValuePool().createIdentifierValue(id); + if (id == CSSValueWebkitText || isValidSystemColorValue(id) || id == CSSValueMenu || id == CSSValueCurrentcolor + || (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode())) + return CSSValuePool::singleton().createIdentifierValue(id); return parseColor(); } -bool CSSParser::parseFillImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value) +bool CSSParser::parseFillImage(CSSParserValueList& valueList, RefPtr<CSSValue>& value) { - if (valueList->current()->id == CSSValueNone) { - value = cssValuePool().createIdentifierValue(CSSValueNone); + if (valueList.current()->id == CSSValueNone) { + value = CSSValuePool::singleton().createIdentifierValue(CSSValueNone); return true; } - if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) { - value = CSSImageValue::create(completeURL(valueList->current()->string)); + if (valueList.current()->unit == CSSPrimitiveValue::CSS_URI) { + value = CSSImageValue::create(completeURL(valueList.current()->string)); return true; } - if (isGeneratedImageValue(valueList->current())) + if (isGeneratedImageValue(*valueList.current())) return parseGeneratedImage(valueList, value); #if ENABLE(CSS_IMAGE_SET) - if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) { + if (valueList.current()->unit == CSSParserValue::Function && equalLettersIgnoringASCIICase(valueList.current()->function->name, "-webkit-image-set(")) { value = parseImageSet(); if (value) return true; @@ -3844,46 +4384,48 @@ bool CSSParser::parseFillImage(CSSParserValueList* valueList, RefPtr<CSSValue>& return false; } -PassRefPtr<CSSValue> CSSParser::parseFillPositionX(CSSParserValueList* valueList) +RefPtr<CSSPrimitiveValue> CSSParser::parsePositionX(CSSParserValueList& valueList) { - int id = valueList->current()->id; + int id = valueList.current()->id; if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) { int percent = 0; if (id == CSSValueRight) percent = 100; else if (id == CSSValueCenter) percent = 50; - return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE); + return CSSValuePool::singleton().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE); } - if (validUnit(valueList->current(), FPercent | FLength)) - return createPrimitiveNumericValue(valueList->current()); - return 0; + ValueWithCalculation valueWithCalculation(*valueList.current()); + if (validateUnit(valueWithCalculation, FPercent | FLength)) + return createPrimitiveNumericValue(valueWithCalculation); + return nullptr; } -PassRefPtr<CSSValue> CSSParser::parseFillPositionY(CSSParserValueList* valueList) +RefPtr<CSSPrimitiveValue> CSSParser::parsePositionY(CSSParserValueList& valueList) { - int id = valueList->current()->id; + int id = valueList.current()->id; if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) { int percent = 0; if (id == CSSValueBottom) percent = 100; else if (id == CSSValueCenter) percent = 50; - return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE); + return CSSValuePool::singleton().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE); } - if (validUnit(valueList->current(), FPercent | FLength)) - return createPrimitiveNumericValue(valueList->current()); - return 0; + ValueWithCalculation valueWithCalculation(*valueList.current()); + if (validateUnit(valueWithCalculation, FPercent | FLength)) + return createPrimitiveNumericValue(valueWithCalculation); + return nullptr; } -PassRefPtr<CSSPrimitiveValue> CSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode) +RefPtr<CSSPrimitiveValue> CSSParser::parseFillPositionComponent(CSSParserValueList& valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode) { - CSSValueID id = valueList->current()->id; + CSSValueID id = valueList.current()->id; if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) { int percent = 0; if (id == CSSValueLeft || id == CSSValueRight) { if (cumulativeFlags & XFillPosition) - return 0; + return nullptr; cumulativeFlags |= XFillPosition; individualFlag = XFillPosition; if (id == CSSValueRight) @@ -3891,7 +4433,7 @@ PassRefPtr<CSSPrimitiveValue> CSSParser::parseFillPositionComponent(CSSParserVal } else if (id == CSSValueTop || id == CSSValueBottom) { if (cumulativeFlags & YFillPosition) - return 0; + return nullptr; cumulativeFlags |= YFillPosition; individualFlag = YFillPosition; if (id == CSSValueBottom) @@ -3904,25 +4446,23 @@ PassRefPtr<CSSPrimitiveValue> CSSParser::parseFillPositionComponent(CSSParserVal } if (parsingMode == ResolveValuesAsKeyword) - return cssValuePool().createIdentifierValue(id); + return CSSValuePool::singleton().createIdentifierValue(id); - return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE); + return CSSValuePool::singleton().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE); } - if (validUnit(valueList->current(), FPercent | FLength)) { + ValueWithCalculation valueWithCalculation(*valueList.current()); + if (validateUnit(valueWithCalculation, FPercent | FLength)) { if (!cumulativeFlags) { cumulativeFlags |= XFillPosition; individualFlag = XFillPosition; } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) { cumulativeFlags |= YFillPosition; individualFlag = YFillPosition; - } else { - if (m_parsedCalculation) - m_parsedCalculation.release(); - return 0; - } - return createPrimitiveNumericValue(valueList->current()); + } else + return nullptr; + return createPrimitiveNumericValue(valueWithCalculation); } - return 0; + return nullptr; } static bool isValueConflictingWithCurrentEdge(int value1, int value2) @@ -3941,7 +4481,7 @@ static bool isFillPositionKeyword(CSSValueID value) return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter; } -void CSSParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtr<CSSPrimitiveValue> parsedValue1, PassRefPtr<CSSPrimitiveValue> parsedValue2) +void CSSParser::parse4ValuesFillPosition(CSSParserValueList& valueList, RefPtr<CSSPrimitiveValue>& value1, RefPtr<CSSPrimitiveValue>& value2, RefPtr<CSSPrimitiveValue>&& parsedValue1, RefPtr<CSSPrimitiveValue>&& parsedValue2) { // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <percentage> | <length> ] // In the case of 4 values <position> requires the second value to be a length or a percentage. @@ -3969,7 +4509,7 @@ void CSSParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtr<C if (isValueConflictingWithCurrentEdge(ident1, ident3)) return; - valueList->next(); + valueList.next(); cumulativeFlags = 0; FillPositionFlag value4Flag = InvalidFillPosition; @@ -3981,15 +4521,15 @@ void CSSParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtr<C if (isFillPositionKeyword(value4->getValueID())) return; - value1 = createPrimitiveValuePair(parsedValue1, parsedValue2); - value2 = createPrimitiveValuePair(value3, value4); + value1 = createPrimitiveValuePair(WTFMove(parsedValue1), WTFMove(parsedValue2)); + value2 = createPrimitiveValuePair(value3.copyRef(), value4.copyRef()); if (ident1 == CSSValueTop || ident1 == CSSValueBottom) value1.swap(value2); - valueList->next(); + valueList.next(); } -void CSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtr<CSSPrimitiveValue> parsedValue1, PassRefPtr<CSSPrimitiveValue> parsedValue2) +void CSSParser::parse3ValuesFillPosition(CSSParserValueList& valueList, RefPtr<CSSPrimitiveValue>& value1, RefPtr<CSSPrimitiveValue>& value2, RefPtr<CSSPrimitiveValue>&& parsedValue1, RefPtr<CSSPrimitiveValue>&& parsedValue2) { unsigned cumulativeFlags = 0; FillPositionFlag value3Flag = InvalidFillPosition; @@ -3999,7 +4539,7 @@ void CSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<C if (!value3) return; - valueList->next(); + valueList.next(); bool swapNeeded = false; CSSValueID ident1 = parsedValue1->getValueID(); @@ -4009,6 +4549,7 @@ void CSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<C CSSValueID firstPositionKeyword; CSSValueID secondPositionKeyword; + auto& cssValuePool = CSSValuePool::singleton(); if (ident1 == CSSValueCenter) { // <position> requires the first 'center' to be followed by a keyword. if (!isFillPositionKeyword(ident2)) @@ -4023,8 +4564,8 @@ void CSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<C firstPositionKeyword = CSSValueTop; swapNeeded = true; } - value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE)); - value2 = createPrimitiveValuePair(parsedValue2, value3); + value1 = createPrimitiveValuePair(cssValuePool.createIdentifierValue(firstPositionKeyword), cssValuePool.createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE)); + value2 = createPrimitiveValuePair(WTFMove(parsedValue2), value3.copyRef()); } else if (ident3 == CSSValueCenter) { if (isFillPositionKeyword(ident2)) return; @@ -4034,8 +4575,8 @@ void CSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<C secondPositionKeyword = CSSValueLeft; swapNeeded = true; } - value1 = createPrimitiveValuePair(parsedValue1, parsedValue2); - value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE)); + value1 = createPrimitiveValuePair(WTFMove(parsedValue1), parsedValue2.copyRef()); + value2 = createPrimitiveValuePair(cssValuePool.createIdentifierValue(secondPositionKeyword), cssValuePool.createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE)); } else { RefPtr<CSSPrimitiveValue> firstPositionValue; RefPtr<CSSPrimitiveValue> secondPositionValue; @@ -4049,7 +4590,7 @@ void CSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<C secondPositionValue = value3; secondPositionKeyword = ident2; - firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE); + firstPositionValue = cssValuePool.createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE); } else { // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ]. if (!isFillPositionKeyword(ident3)) @@ -4057,40 +4598,43 @@ void CSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<C firstPositionValue = parsedValue2; secondPositionKeyword = ident3; - secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE); + secondPositionValue = cssValuePool.createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE); } if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword)) return; - value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue); - value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue); + value1 = createPrimitiveValuePair(WTFMove(parsedValue1), firstPositionValue.copyRef()); + value2 = createPrimitiveValuePair(cssValuePool.createIdentifierValue(secondPositionKeyword), secondPositionValue.copyRef()); } if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded) value1.swap(value2); #ifndef NDEBUG - CSSPrimitiveValue* first = static_cast<CSSPrimitiveValue*>(value1.get()); - CSSPrimitiveValue* second = static_cast<CSSPrimitiveValue*>(value2.get()); - ident1 = first->getPairValue()->first()->getValueID(); - ident2 = second->getPairValue()->first()->getValueID(); + CSSPrimitiveValue& first = *value1; + CSSPrimitiveValue& second = *value2; + ident1 = first.getPairValue()->first()->getValueID(); + ident2 = second.getPairValue()->first()->getValueID(); ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight); ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop); #endif } -inline bool CSSParser::isPotentialPositionValue(CSSParserValue* value) +inline bool CSSParser::isPotentialPositionValue(CSSParserValue& value) { - return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue); + if (isFillPositionKeyword(value.id)) + return true; + ValueWithCalculation valueWithCalculation(value); + return validateUnit(valueWithCalculation, FPercent | FLength); } -void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2) +void CSSParser::parseFillPosition(CSSParserValueList& valueList, RefPtr<CSSPrimitiveValue>& value1, RefPtr<CSSPrimitiveValue>& value2) { unsigned numberOfValues = 0; - for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++numberOfValues) { - CSSParserValue* current = valueList->valueAt(i); - if (isComma(current) || !current || isForwardSlashOperator(current) || !isPotentialPositionValue(current)) + for (unsigned i = valueList.currentIndex(); i < valueList.size(); ++i, ++numberOfValues) { + CSSParserValue* current = valueList.valueAt(i); + if (!current || isComma(current) || isForwardSlashOperator(*current) || !isPotentialPositionValue(*current)) break; } @@ -4105,7 +4649,7 @@ void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue ASSERT(numberOfValues > 2 && numberOfValues <= 4); - CSSParserValue* value = valueList->current(); + CSSParserValue* value = valueList.current(); // <position> requires the first value to be a background keyword. if (!isFillPositionKeyword(value->id)) @@ -4119,38 +4663,38 @@ void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue if (!value1) return; - value = valueList->next(); + value = valueList.next(); // In case we are parsing more than two values, relax the check inside of parseFillPositionComponent. top 20px is // a valid start for <position>. cumulativeFlags = AmbiguousFillPosition; value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword); if (value2) - valueList->next(); + valueList.next(); else { - value1.clear(); + value1 = nullptr; return; } - RefPtr<CSSPrimitiveValue> parsedValue1 = static_cast<CSSPrimitiveValue*>(value1.get()); - RefPtr<CSSPrimitiveValue> parsedValue2 = static_cast<CSSPrimitiveValue*>(value2.get()); + RefPtr<CSSPrimitiveValue> parsedValue1 = value1; + RefPtr<CSSPrimitiveValue> parsedValue2 = value2; - value1.clear(); - value2.clear(); + value1 = nullptr; + value2 = nullptr; // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow. if (parsedValue2->getValueID() == CSSValueCenter) return; if (numberOfValues == 3) - parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release()); + parse3ValuesFillPosition(valueList, value1, value2, WTFMove(parsedValue1), WTFMove(parsedValue2)); else - parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release()); + parse4ValuesFillPosition(valueList, value1, value2, WTFMove(parsedValue1), WTFMove(parsedValue2)); } -void CSSParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2) +void CSSParser::parse2ValuesFillPosition(CSSParserValueList& valueList, RefPtr<CSSPrimitiveValue>& value1, RefPtr<CSSPrimitiveValue>& value2) { - CSSParserValue* value = valueList->current(); + CSSParserValue* value = valueList.current(); // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length. unsigned cumulativeFlags = 0; @@ -4163,19 +4707,19 @@ void CSSParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtr<C // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the // value was explicitly specified for our property. - value = valueList->next(); + value = valueList.next(); // First check for the comma. If so, we are finished parsing this value or value pair. if (isComma(value)) - value = 0; + value = nullptr; if (value) { value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag); if (value2) - valueList->next(); + valueList.next(); else { if (!inShorthand()) { - value1.clear(); + value1 = nullptr; return; } } @@ -4186,7 +4730,7 @@ void CSSParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtr<C // is simply 50%. This is our default. // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center). // For left/right/center, the default of 50% in the y is still correct. - value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE); + value2 = CSSValuePool::singleton().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE); if (value1Flag == YFillPosition || value2Flag == XFillPosition) value1.swap(value2); @@ -4197,22 +4741,22 @@ void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& valu CSSValueID id = m_valueList->current()->id; if (id == CSSValueRepeatX) { m_implicitShorthand = true; - value1 = cssValuePool().createIdentifierValue(CSSValueRepeat); - value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat); + value1 = CSSValuePool::singleton().createIdentifierValue(CSSValueRepeat); + value2 = CSSValuePool::singleton().createIdentifierValue(CSSValueNoRepeat); m_valueList->next(); return; } if (id == CSSValueRepeatY) { m_implicitShorthand = true; - value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat); - value2 = cssValuePool().createIdentifierValue(CSSValueRepeat); + value1 = CSSValuePool::singleton().createIdentifierValue(CSSValueNoRepeat); + value2 = CSSValuePool::singleton().createIdentifierValue(CSSValueRepeat); m_valueList->next(); return; } if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) - value1 = cssValuePool().createIdentifierValue(id); + value1 = CSSValuePool::singleton().createIdentifierValue(id); else { - value1 = 0; + value1 = nullptr; return; } @@ -4222,7 +4766,7 @@ void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& valu if (value && !isComma(value)) { id = value->id; if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) { - value2 = cssValuePool().createIdentifierValue(id); + value2 = CSSValuePool::singleton().createIdentifierValue(id); m_valueList->next(); return; } @@ -4230,25 +4774,26 @@ void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& valu // If only one value was specified, value2 is the same as value1. m_implicitShorthand = true; - value2 = cssValuePool().createIdentifierValue(static_cast<CSSPrimitiveValue*>(value1.get())->getValueID()); + value2 = CSSValuePool::singleton().createIdentifierValue(downcast<CSSPrimitiveValue>(*value1).getValueID()); } -PassRefPtr<CSSValue> CSSParser::parseFillSize(CSSPropertyID propId, bool& allowComma) +RefPtr<CSSValue> CSSParser::parseFillSize(CSSPropertyID propId, bool& allowComma) { allowComma = true; CSSParserValue* value = m_valueList->current(); if (value->id == CSSValueContain || value->id == CSSValueCover) - return cssValuePool().createIdentifierValue(value->id); + return CSSValuePool::singleton().createIdentifierValue(value->id); RefPtr<CSSPrimitiveValue> parsedValue1; if (value->id == CSSValueAuto) - parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto); + parsedValue1 = CSSValuePool::singleton().createIdentifierValue(CSSValueAuto); else { - if (!validUnit(value, FLength | FPercent)) - return 0; - parsedValue1 = createPrimitiveNumericValue(value); + ValueWithCalculation valueWithCalculation(*value); + if (!validateUnit(valueWithCalculation, FLength | FPercent)) + return nullptr; + parsedValue1 = createPrimitiveNumericValue(valueWithCalculation); } RefPtr<CSSPrimitiveValue> parsedValue2; @@ -4256,13 +4801,14 @@ PassRefPtr<CSSValue> CSSParser::parseFillSize(CSSPropertyID propId, bool& allowC if (value->unit == CSSParserValue::Operator && value->iValue == ',') allowComma = false; else if (value->id != CSSValueAuto) { - if (!validUnit(value, FLength | FPercent)) { + ValueWithCalculation valueWithCalculation(*value); + if (!validateUnit(valueWithCalculation, FLength | FPercent)) { if (!inShorthand()) - return 0; + return nullptr; // We need to rewind the value list, so that when it is advanced we'll end up back at this value. m_valueList->previous(); } else - parsedValue2 = createPrimitiveNumericValue(value); + parsedValue2 = createPrimitiveNumericValue(valueWithCalculation); } } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) { // For backwards compatibility we set the second value to the first if it is omitted. @@ -4273,7 +4819,7 @@ PassRefPtr<CSSValue> CSSParser::parseFillSize(CSSPropertyID propId, bool& allowC if (!parsedValue2) return parsedValue1; - return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()); + return createPrimitiveValuePair(WTFMove(parsedValue1), WTFMove(parsedValue2), propId == CSSPropertyWebkitBackgroundSize ? Pair::IdenticalValueEncoding::Coalesce : Pair::IdenticalValueEncoding::DoNotCoalesce); } bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, @@ -4281,13 +4827,13 @@ bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, { RefPtr<CSSValueList> values; RefPtr<CSSValueList> values2; - CSSParserValue* val; + CSSParserValue* currentValue; RefPtr<CSSValue> value; RefPtr<CSSValue> value2; bool allowComma = false; - retValue1 = retValue2 = 0; + retValue1 = retValue2 = nullptr; propId1 = propId; propId2 = propId; if (propId == CSSPropertyBackgroundPosition) { @@ -4304,12 +4850,12 @@ bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, propId2 = CSSPropertyWebkitMaskRepeatY; } - while ((val = m_valueList->current())) { + while ((currentValue = m_valueList->current())) { RefPtr<CSSValue> currValue; RefPtr<CSSValue> currValue2; if (allowComma) { - if (!isComma(val)) + if (!isComma(currentValue)) return false; m_valueList->next(); allowComma = false; @@ -4322,14 +4868,14 @@ bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, m_valueList->next(); break; case CSSPropertyBackgroundAttachment: - if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) { - currValue = cssValuePool().createIdentifierValue(val->id); + if (currentValue->id == CSSValueScroll || currentValue->id == CSSValueFixed || currentValue->id == CSSValueLocal) { + currValue = CSSValuePool::singleton().createIdentifierValue(currentValue->id); m_valueList->next(); } break; case CSSPropertyBackgroundImage: case CSSPropertyWebkitMaskImage: - if (parseFillImage(m_valueList.get(), currValue)) + if (parseFillImage(*m_valueList, currValue)) m_valueList->next(); break; case CSSPropertyWebkitBackgroundClip: @@ -4338,58 +4884,62 @@ bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, case CSSPropertyWebkitMaskOrigin: // The first three values here are deprecated and do not apply to the version of the property that has // the -webkit- prefix removed. - if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent || - val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox || - ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) && - (val->id == CSSValueText || val->id == CSSValueWebkitText))) { - currValue = cssValuePool().createIdentifierValue(val->id); + if (currentValue->id == CSSValueBorder || currentValue->id == CSSValuePadding || currentValue->id == CSSValueContent + || currentValue->id == CSSValueBorderBox || currentValue->id == CSSValuePaddingBox || currentValue->id == CSSValueContentBox + || ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) + && (currentValue->id == CSSValueText || currentValue->id == CSSValueWebkitText))) { + currValue = CSSValuePool::singleton().createIdentifierValue(currentValue->id); m_valueList->next(); } break; case CSSPropertyBackgroundClip: - if (parseBackgroundClip(val, currValue)) + if (parseBackgroundClip(*currentValue, currValue)) m_valueList->next(); break; case CSSPropertyBackgroundOrigin: - if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) { - currValue = cssValuePool().createIdentifierValue(val->id); + if (currentValue->id == CSSValueBorderBox || currentValue->id == CSSValuePaddingBox || currentValue->id == CSSValueContentBox) { + currValue = CSSValuePool::singleton().createIdentifierValue(currentValue->id); m_valueList->next(); } break; case CSSPropertyBackgroundPosition: - case CSSPropertyWebkitMaskPosition: - parseFillPosition(m_valueList.get(), currValue, currValue2); + case CSSPropertyWebkitMaskPosition: { + RefPtr<CSSPrimitiveValue> value1; + RefPtr<CSSPrimitiveValue> value2; + parseFillPosition(*m_valueList, value1, value2); + currValue = value1; + currValue2 = value2; // parseFillPosition advances the m_valueList pointer. break; + } case CSSPropertyBackgroundPositionX: case CSSPropertyWebkitMaskPositionX: { - currValue = parseFillPositionX(m_valueList.get()); + currValue = parsePositionX(*m_valueList); if (currValue) m_valueList->next(); break; } case CSSPropertyBackgroundPositionY: case CSSPropertyWebkitMaskPositionY: { - currValue = parseFillPositionY(m_valueList.get()); + currValue = parsePositionY(*m_valueList); if (currValue) m_valueList->next(); break; } case CSSPropertyWebkitBackgroundComposite: case CSSPropertyWebkitMaskComposite: - if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) { - currValue = cssValuePool().createIdentifierValue(val->id); + if (currentValue->id >= CSSValueClear && currentValue->id <= CSSValuePlusLighter) { + currValue = CSSValuePool::singleton().createIdentifierValue(currentValue->id); m_valueList->next(); } break; - case CSSPropertyWebkitBackgroundBlendMode: - if (cssCompositingEnabled() && (val->id == CSSValueNormal || val->id == CSSValueMultiply - || val->id == CSSValueScreen || val->id == CSSValueOverlay || val->id == CSSValueDarken - || val->id == CSSValueLighten || val->id == CSSValueColorDodge || val->id == CSSValueColorBurn - || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference - || val->id == CSSValueExclusion || val->id == CSSValueHue || val->id == CSSValueSaturation - || val->id == CSSValueColor || val->id == CSSValueLuminosity)) { - currValue = cssValuePool().createIdentifierValue(val->id); + case CSSPropertyBackgroundBlendMode: + if (cssCompositingEnabled() && (currentValue->id == CSSValueNormal || currentValue->id == CSSValueMultiply + || currentValue->id == CSSValueScreen || currentValue->id == CSSValueOverlay || currentValue->id == CSSValueDarken + || currentValue->id == CSSValueLighten || currentValue->id == CSSValueColorDodge || currentValue->id == CSSValueColorBurn + || currentValue->id == CSSValueHardLight || currentValue->id == CSSValueSoftLight || currentValue->id == CSSValueDifference + || currentValue->id == CSSValueExclusion)) { + currValue = CSSValuePool::singleton().createIdentifierValue(currentValue->id); m_valueList->next(); } break; @@ -4406,6 +4956,14 @@ bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, m_valueList->next(); break; } + case CSSPropertyWebkitMaskSourceType: { + if (currentValue->id == CSSValueAuto || currentValue->id == CSSValueAlpha || currentValue->id == CSSValueLuminance) { + currValue = CSSValuePool::singleton().createIdentifierValue(currentValue->id); + m_valueList->next(); + } else + currValue = nullptr; + break; + } default: break; } @@ -4414,21 +4972,21 @@ bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, if (value && !values) { values = CSSValueList::createCommaSeparated(); - values->append(value.release()); + values->append(value.releaseNonNull()); } if (value2 && !values2) { values2 = CSSValueList::createCommaSeparated(); - values2->append(value2.release()); + values2->append(value2.releaseNonNull()); } if (values) - values->append(currValue.release()); + values->append(currValue.releaseNonNull()); else value = currValue.release(); if (currValue2) { if (values2) - values2->append(currValue2.release()); + values2->append(currValue2.releaseNonNull()); else value2 = currValue2.release(); } @@ -4454,190 +5012,268 @@ bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, return false; } -PassRefPtr<CSSValue> CSSParser::parseAnimationDelay() +RefPtr<CSSValue> CSSParser::parseAnimationDelay() { - CSSParserValue* value = m_valueList->current(); - if (validUnit(value, FTime)) - return createPrimitiveNumericValue(value); - return 0; + ValueWithCalculation valueWithCalculation(*m_valueList->current()); + if (validateUnit(valueWithCalculation, FTime)) + return createPrimitiveNumericValue(valueWithCalculation); + return nullptr; } -PassRefPtr<CSSValue> CSSParser::parseAnimationDirection() +RefPtr<CSSValue> CSSParser::parseAnimationDirection() { CSSParserValue* value = m_valueList->current(); if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse) - return cssValuePool().createIdentifierValue(value->id); - return 0; + return CSSValuePool::singleton().createIdentifierValue(value->id); + return nullptr; } -PassRefPtr<CSSValue> CSSParser::parseAnimationDuration() +RefPtr<CSSValue> CSSParser::parseAnimationDuration() { - CSSParserValue* value = m_valueList->current(); - if (validUnit(value, FTime | FNonNeg)) - return createPrimitiveNumericValue(value); - return 0; + ValueWithCalculation valueWithCalculation(*m_valueList->current()); + if (validateUnit(valueWithCalculation, FTime | FNonNeg)) + return createPrimitiveNumericValue(valueWithCalculation); + return nullptr; } -PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode() +RefPtr<CSSValue> CSSParser::parseAnimationFillMode() { CSSParserValue* value = m_valueList->current(); if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth) - return cssValuePool().createIdentifierValue(value->id); - return 0; + return CSSValuePool::singleton().createIdentifierValue(value->id); + return nullptr; } -PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount() +RefPtr<CSSValue> CSSParser::parseAnimationIterationCount() { - CSSParserValue* value = m_valueList->current(); - if (value->id == CSSValueInfinite) - return cssValuePool().createIdentifierValue(value->id); - if (validUnit(value, FNumber | FNonNeg)) - return createPrimitiveNumericValue(value); - return 0; + CSSParserValue& value = *m_valueList->current(); + if (value.id == CSSValueInfinite) + return CSSValuePool::singleton().createIdentifierValue(value.id); + ValueWithCalculation valueWithCalculation(value); + if (validateUnit(valueWithCalculation, FNumber | FNonNeg)) + return createPrimitiveNumericValue(valueWithCalculation); + return nullptr; } -PassRefPtr<CSSValue> CSSParser::parseAnimationName() +RefPtr<CSSValue> CSSParser::parseAnimationName() { - CSSParserValue* value = m_valueList->current(); - if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) { - if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value, "none"))) { - return cssValuePool().createIdentifierValue(CSSValueNone); - } else { - return createPrimitiveStringValue(value); + CSSParserValue& value = *m_valueList->current(); + if (value.unit == CSSPrimitiveValue::CSS_STRING || value.unit == CSSPrimitiveValue::CSS_IDENT) { + if (value.id == CSSValueNone || (value.unit == CSSPrimitiveValue::CSS_STRING && equalLettersIgnoringASCIICase(value, "none"))) { + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); } + return createPrimitiveStringValue(value); } - return 0; + return nullptr; } -PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState() +RefPtr<CSSValue> CSSParser::parseAnimationPlayState() { - CSSParserValue* value = m_valueList->current(); - if (value->id == CSSValueRunning || value->id == CSSValuePaused) - return cssValuePool().createIdentifierValue(value->id); - return 0; + CSSParserValue& value = *m_valueList->current(); + if (value.id == CSSValueRunning || value.id == CSSValuePaused) + return CSSValuePool::singleton().createIdentifierValue(value.id); + return nullptr; } -PassRefPtr<CSSValue> CSSParser::parseAnimationProperty(AnimationParseContext& context) +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) +RefPtr<CSSValue> CSSParser::parseAnimationTrigger() { CSSParserValue* value = m_valueList->current(); - if (value->unit != CSSPrimitiveValue::CSS_IDENT) - return 0; - CSSPropertyID result = cssPropertyID(value->string); - if (result) - return cssValuePool().createIdentifierValue(result); - if (equalIgnoringCase(value, "all")) { + if (value->id == CSSValueAuto) + return CSSValuePool::singleton().createIdentifierValue(CSSValueAuto); + + if (value->unit != CSSParserValue::Function) + return nullptr; + + CSSParserValueList* args = value->function->args.get(); + + if (equalLettersIgnoringASCIICase(value->function->name, "container-scroll(")) { + if (!args || (args->size() != 1 && args->size() != 3)) + return nullptr; + + CSSParserValue* argument = args->current(); + ValueWithCalculation firstArgumentWithCalculation(*argument); + if (!validateUnit(firstArgumentWithCalculation, FLength)) + return nullptr; + + RefPtr<CSSValue> startValue = createPrimitiveNumericValue(firstArgumentWithCalculation); + + argument = args->next(); + + if (!argument) + return CSSAnimationTriggerScrollValue::create(startValue.release()); + + if (!isComma(argument)) + return nullptr; + + argument = args->next(); + ValueWithCalculation secondArgumentWithCalculation(*argument); + if (!validateUnit(secondArgumentWithCalculation, FLength)) + return nullptr; + + RefPtr<CSSValue> endValue = createPrimitiveNumericValue(secondArgumentWithCalculation); + + return CSSAnimationTriggerScrollValue::create(startValue.release(), endValue.release()); + } + + return nullptr; +} +#endif + +RefPtr<CSSValue> CSSParser::parseAnimationProperty(AnimationParseContext& context) +{ + CSSParserValue& value = *m_valueList->current(); + if (value.unit != CSSPrimitiveValue::CSS_IDENT) + return nullptr; + CSSPropertyID result = cssPropertyID(value.string); + if (result && result != CSSPropertyAll) // "all" value in animation is not equivalent to the all property. + return CSSValuePool::singleton().createIdentifierValue(result); + if (equalLettersIgnoringASCIICase(value, "all")) { context.sawAnimationPropertyKeyword(); - return cssValuePool().createIdentifierValue(CSSValueAll); + return CSSValuePool::singleton().createIdentifierValue(CSSValueAll); } - if (equalIgnoringCase(value, "none")) { + if (equalLettersIgnoringASCIICase(value, "none")) { context.commitAnimationPropertyKeyword(); context.sawAnimationPropertyKeyword(); - return cssValuePool().createIdentifierValue(CSSValueNone); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); } - return 0; + return nullptr; } -bool CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3) +/* static */ +Vector<double> CSSParser::parseKeyframeSelector(const String& selector) { + Vector<double> keys; + Vector<String> strings; + selector.split(',', strings); + + for (size_t i = 0; i < strings.size(); ++i) { + double key = -1; + String cur = strings[i].stripWhiteSpace(); + + // For now the syntax MUST be 'xxx%' or 'from' or 'to', where xxx is a legal floating point number + if (equalLettersIgnoringASCIICase(cur, "from")) + key = 0; + else if (equalLettersIgnoringASCIICase(cur, "to")) + key = 1; + else if (cur.endsWith('%')) { + double k = cur.substring(0, cur.length() - 1).toDouble(); + if (k >= 0 && k <= 100) + key = k / 100; + } + if (key < 0) { + keys.clear(); + break; + } + keys.append(key); + } + + return keys; +} + +bool CSSParser::parseTransformOriginShorthand(RefPtr<CSSPrimitiveValue>& value1, RefPtr<CSSPrimitiveValue>& value2, RefPtr<CSSValue>& value3) { - parse2ValuesFillPosition(m_valueList.get(), value1, value2); + parse2ValuesFillPosition(*m_valueList, value1, value2); // now get z if (m_valueList->current()) { - if (validUnit(m_valueList->current(), FLength)) { - value3 = createPrimitiveNumericValue(m_valueList->current()); + ValueWithCalculation valueWithCalculation(*m_valueList->current()); + if (validateUnit(valueWithCalculation, FLength)) { + value3 = createPrimitiveNumericValue(valueWithCalculation); m_valueList->next(); return true; } return false; } - value3 = cssValuePool().createImplicitInitialValue(); + value3 = CSSValuePool::singleton().createImplicitInitialValue(); return true; } -bool CSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result) +bool CSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList& args, double& result) { - CSSParserValue* v = args->current(); - if (!validUnit(v, FNumber)) + ValueWithCalculation argumentWithCalculation(*args.current()); + if (!validateUnit(argumentWithCalculation, FNumber)) return false; - result = v->fValue; - v = args->next(); - if (!v) + result = parsedDouble(argumentWithCalculation); + CSSParserValue* nextValue = args.next(); + if (!nextValue) { // The last number in the function has no comma after it, so we're done. return true; - if (!isComma(v)) + } + if (!isComma(nextValue)) return false; - args->next(); + args.next(); return true; } -PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction() +RefPtr<CSSValue> CSSParser::parseAnimationTimingFunction() { - CSSParserValue* value = m_valueList->current(); - if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut - || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd) - return cssValuePool().createIdentifierValue(value->id); + CSSParserValue& value = *m_valueList->current(); + if (value.id == CSSValueEase || value.id == CSSValueLinear || value.id == CSSValueEaseIn || value.id == CSSValueEaseOut + || value.id == CSSValueEaseInOut || value.id == CSSValueStepStart || value.id == CSSValueStepEnd) + return CSSValuePool::singleton().createIdentifierValue(value.id); // We must be a function. - if (value->unit != CSSParserValue::Function) - return 0; + if (value.unit != CSSParserValue::Function) + return nullptr; - CSSParserValueList* args = value->function->args.get(); + CSSParserValueList* args = value.function->args.get(); - if (equalIgnoringCase(value->function->name, "steps(")) { + if (equalLettersIgnoringASCIICase(value.function->name, "steps(")) { // For steps, 1 or 2 params must be specified (comma-separated) if (!args || (args->size() != 1 && args->size() != 3)) - return 0; + return nullptr; // There are two values. int numSteps; bool stepAtStart = false; - CSSParserValue* v = args->current(); - if (!validUnit(v, FInteger)) - return 0; - numSteps = clampToInteger(v->fValue); + CSSParserValue* argument = args->current(); + ValueWithCalculation argumentWithCalculation(*argument); + if (!validateUnit(argumentWithCalculation, FInteger)) + return nullptr; + numSteps = clampToInteger(parsedDouble(argumentWithCalculation)); if (numSteps < 1) - return 0; - v = args->next(); + return nullptr; + argument = args->next(); - if (v) { + if (argument) { // There is a comma so we need to parse the second value - if (!isComma(v)) - return 0; - v = args->next(); - if (v->id != CSSValueStart && v->id != CSSValueEnd) - return 0; - stepAtStart = v->id == CSSValueStart; + if (!isComma(argument)) + return nullptr; + argument = args->next(); + if (argument->id != CSSValueStart && argument->id != CSSValueEnd) + return nullptr; + stepAtStart = argument->id == CSSValueStart; } return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart); } - if (equalIgnoringCase(value->function->name, "cubic-bezier(")) { + if (equalLettersIgnoringASCIICase(value.function->name, "cubic-bezier(")) { // For cubic bezier, 4 values must be specified. if (!args || args->size() != 7) - return 0; + return nullptr; // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range. double x1, y1, x2, y2; - if (!parseCubicBezierTimingFunctionValue(args, x1)) - return 0; + if (!parseCubicBezierTimingFunctionValue(*args, x1)) + return nullptr; if (x1 < 0 || x1 > 1) - return 0; - if (!parseCubicBezierTimingFunctionValue(args, y1)) - return 0; - if (!parseCubicBezierTimingFunctionValue(args, x2)) - return 0; + return nullptr; + if (!parseCubicBezierTimingFunctionValue(*args, y1)) + return nullptr; + if (!parseCubicBezierTimingFunctionValue(*args, x2)) + return nullptr; if (x2 < 0 || x2 > 1) - return 0; - if (!parseCubicBezierTimingFunctionValue(args, y2)) - return 0; + return nullptr; + if (!parseCubicBezierTimingFunctionValue(*args, y2)) + return nullptr; return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2); } - return 0; + return nullptr; } bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& result, AnimationParseContext& context) @@ -4647,7 +5283,7 @@ bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& r RefPtr<CSSValue> value; bool allowComma = false; - result = 0; + result = nullptr; while ((val = m_valueList->current())) { RefPtr<CSSValue> currValue; @@ -4659,63 +5295,78 @@ bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& r } else { switch (propId) { - case CSSPropertyWebkitAnimationDelay: - case CSSPropertyTransitionDelay: - case CSSPropertyWebkitTransitionDelay: - currValue = parseAnimationDelay(); - if (currValue) - m_valueList->next(); - break; - case CSSPropertyWebkitAnimationDirection: - currValue = parseAnimationDirection(); - if (currValue) - m_valueList->next(); - break; - case CSSPropertyWebkitAnimationDuration: - case CSSPropertyTransitionDuration: - case CSSPropertyWebkitTransitionDuration: - currValue = parseAnimationDuration(); - if (currValue) - m_valueList->next(); - break; - case CSSPropertyWebkitAnimationFillMode: - currValue = parseAnimationFillMode(); - if (currValue) - m_valueList->next(); - break; - case CSSPropertyWebkitAnimationIterationCount: - currValue = parseAnimationIterationCount(); - if (currValue) - m_valueList->next(); - break; - case CSSPropertyWebkitAnimationName: - currValue = parseAnimationName(); - if (currValue) - m_valueList->next(); - break; - case CSSPropertyWebkitAnimationPlayState: - currValue = parseAnimationPlayState(); - if (currValue) - m_valueList->next(); - break; - case CSSPropertyTransitionProperty: - case CSSPropertyWebkitTransitionProperty: - currValue = parseAnimationProperty(context); - if (value && !context.animationPropertyKeywordAllowed()) - return false; - if (currValue) - m_valueList->next(); - break; - case CSSPropertyWebkitAnimationTimingFunction: - case CSSPropertyTransitionTimingFunction: - case CSSPropertyWebkitTransitionTimingFunction: - currValue = parseAnimationTimingFunction(); - if (currValue) - m_valueList->next(); - break; - default: - ASSERT_NOT_REACHED(); + case CSSPropertyAnimationDelay: + case CSSPropertyWebkitAnimationDelay: + case CSSPropertyTransitionDelay: + case CSSPropertyWebkitTransitionDelay: + currValue = parseAnimationDelay(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyAnimationDirection: + case CSSPropertyWebkitAnimationDirection: + currValue = parseAnimationDirection(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyAnimationDuration: + case CSSPropertyWebkitAnimationDuration: + case CSSPropertyTransitionDuration: + case CSSPropertyWebkitTransitionDuration: + currValue = parseAnimationDuration(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyAnimationFillMode: + case CSSPropertyWebkitAnimationFillMode: + currValue = parseAnimationFillMode(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyAnimationIterationCount: + case CSSPropertyWebkitAnimationIterationCount: + currValue = parseAnimationIterationCount(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyAnimationName: + case CSSPropertyWebkitAnimationName: + currValue = parseAnimationName(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyAnimationPlayState: + case CSSPropertyWebkitAnimationPlayState: + currValue = parseAnimationPlayState(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyTransitionProperty: + case CSSPropertyWebkitTransitionProperty: + currValue = parseAnimationProperty(context); + if (value && !context.animationPropertyKeywordAllowed()) return false; + if (currValue) + m_valueList->next(); + break; + case CSSPropertyAnimationTimingFunction: + case CSSPropertyWebkitAnimationTimingFunction: + case CSSPropertyTransitionTimingFunction: + case CSSPropertyWebkitTransitionTimingFunction: + currValue = parseAnimationTimingFunction(); + if (currValue) + m_valueList->next(); + break; +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + case CSSPropertyWebkitAnimationTrigger: + currValue = parseAnimationTrigger(); + if (currValue) + m_valueList->next(); + break; +#endif + default: + ASSERT_NOT_REACHED(); + return false; } if (!currValue) @@ -4723,11 +5374,11 @@ bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& r if (value && !values) { values = CSSValueList::createCommaSeparated(); - values->append(value.release()); + values->append(value.releaseNonNull()); } if (values) - values->append(currValue.release()); + values->append(currValue.releaseNonNull()); else value = currValue.release(); @@ -4751,94 +5402,620 @@ bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& r return false; } +#if ENABLE(CSS_GRID_LAYOUT) +static inline bool isValidGridPositionCustomIdent(const CSSParserValue& value) +{ + return value.unit == CSSPrimitiveValue::CSS_IDENT && value.id != CSSValueSpan && value.id != CSSValueAuto; +} + +// The function parses [ <integer> || <custom-ident> ] in <grid-line> (which can be stand alone or with 'span'). +bool CSSParser::parseIntegerOrCustomIdentFromGridPosition(RefPtr<CSSPrimitiveValue>& numericValue, RefPtr<CSSPrimitiveValue>& gridLineName) +{ + ValueWithCalculation valueWithCalculation(*m_valueList->current()); + if (validateUnit(valueWithCalculation, FInteger) && valueWithCalculation.value().fValue) { + numericValue = createPrimitiveNumericValue(valueWithCalculation); + CSSParserValue* nextValue = m_valueList->next(); + if (nextValue && isValidGridPositionCustomIdent(*nextValue)) { + gridLineName = createPrimitiveStringValue(*nextValue); + m_valueList->next(); + } + return true; + } + + if (isValidGridPositionCustomIdent(valueWithCalculation)) { + gridLineName = createPrimitiveStringValue(valueWithCalculation); + if (CSSParserValue* nextValue = m_valueList->next()) { + ValueWithCalculation nextValueWithCalculation(*nextValue); + if (validateUnit(nextValueWithCalculation, FInteger) && nextValueWithCalculation.value().fValue) { + numericValue = createPrimitiveNumericValue(nextValueWithCalculation); + m_valueList->next(); + } + } + return true; + } + + return false; +} + +RefPtr<CSSValue> CSSParser::parseGridPosition() +{ + CSSParserValue* value = m_valueList->current(); + if (value->id == CSSValueAuto) { + m_valueList->next(); + return CSSValuePool::singleton().createIdentifierValue(CSSValueAuto); + } + + RefPtr<CSSPrimitiveValue> numericValue; + RefPtr<CSSPrimitiveValue> gridLineName; + bool hasSeenSpanKeyword = false; + + if (value->id == CSSValueSpan) { + hasSeenSpanKeyword = true; + if (auto* nextValue = m_valueList->next()) { + if (!isForwardSlashOperator(*nextValue) && !parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName)) + return nullptr; + } + } else if (parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName)) { + value = m_valueList->current(); + if (value && value->id == CSSValueSpan) { + hasSeenSpanKeyword = true; + m_valueList->next(); + } + } + + // Check that we have consumed all the value list. For shorthands, the parser will pass + // the whole value list (including the opposite position). + if (m_valueList->current() && !isForwardSlashOperator(*m_valueList->current())) + return nullptr; + + // If we didn't parse anything, this is not a valid grid position. + if (!hasSeenSpanKeyword && !gridLineName && !numericValue) + return nullptr; + + // Negative numbers are not allowed for span (but are for <integer>). + if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0) + return nullptr; + + // For the <custom-ident> case. + if (gridLineName && !numericValue && !hasSeenSpanKeyword) + return CSSValuePool::singleton().createValue(gridLineName->getStringValue(), CSSPrimitiveValue::CSS_STRING); + + RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated(); + if (hasSeenSpanKeyword) + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueSpan)); + if (numericValue) + values->append(numericValue.releaseNonNull()); + if (gridLineName) + values->append(gridLineName.releaseNonNull()); + ASSERT(values->length()); + return values; +} + +static RefPtr<CSSValue> gridMissingGridPositionValue(CSSValue& value) +{ + if (is<CSSPrimitiveValue>(value) && downcast<CSSPrimitiveValue>(value).isString()) + return &value; + + return CSSValuePool::singleton().createIdentifierValue(CSSValueAuto); +} + bool CSSParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important) { ShorthandScope scope(this, shorthandId); const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId); ASSERT(shorthand.length() == 2); - if (!parseValue(shorthand.properties()[0], important)) + + RefPtr<CSSValue> startValue = parseGridPosition(); + if (!startValue) return false; - if (!m_valueList->current()) { - // Only one value was specified, the opposite value should be set to 'auto'. - // FIXME: If the first property was <ident>, the opposite value should be the same <ident>. - addProperty(shorthand.properties()[1], cssValuePool().createIdentifierValue(CSSValueAuto), important); + RefPtr<CSSValue> endValue; + if (m_valueList->current()) { + if (!isForwardSlashOperator(*m_valueList->current())) + return false; + + if (!m_valueList->next()) + return false; + + endValue = parseGridPosition(); + if (!endValue || m_valueList->current()) + return false; + } else + endValue = gridMissingGridPositionValue(*startValue); + + addProperty(shorthand.properties()[0], startValue, important); + addProperty(shorthand.properties()[1], endValue, important); + return true; +} + +bool CSSParser::parseGridGapShorthand(bool important) +{ + ShorthandScope scope(this, CSSPropertyWebkitGridGap); + ASSERT(shorthandForProperty(CSSPropertyWebkitGridGap).length() == 2); + + CSSParserValue* value = m_valueList->current(); + if (!value) + return false; + + ValueWithCalculation columnValueWithCalculation(*value); + if (!validateUnit(columnValueWithCalculation, FLength | FNonNeg)) + return false; + + RefPtr<CSSPrimitiveValue> columnGap = createPrimitiveNumericValue(columnValueWithCalculation); + + value = m_valueList->next(); + if (!value) { + addProperty(CSSPropertyWebkitGridColumnGap, columnGap, important); + addProperty(CSSPropertyWebkitGridRowGap, columnGap, important); return true; } - if (!isForwardSlashOperator(m_valueList->current())) + ValueWithCalculation rowValueWithCalculation(*value); + if (!validateUnit(rowValueWithCalculation, FLength | FNonNeg)) return false; - if (!m_valueList->next()) + if (m_valueList->next()) return false; - return parseValue(shorthand.properties()[1], important); + RefPtr<CSSPrimitiveValue> rowGap = createPrimitiveNumericValue(rowValueWithCalculation); + + addProperty(CSSPropertyWebkitGridColumnGap, columnGap, important); + addProperty(CSSPropertyWebkitGridRowGap, rowGap, important); + + return true; } -bool CSSParser::parseGridTrackList(CSSPropertyID propId, bool important) +bool CSSParser::parseGridTemplateRowsAndAreas(PassRefPtr<CSSValue> templateColumns, bool important) { - CSSParserValue* value = m_valueList->current(); - if (value->id == CSSValueNone) { - if (m_valueList->next()) + // At least template-areas strings must be defined. + if (!m_valueList->current()) + return false; + + NamedGridAreaMap gridAreaMap; + unsigned rowCount = 0; + unsigned columnCount = 0; + bool trailingIdentWasAdded = false; + RefPtr<CSSValueList> templateRows = CSSValueList::createSpaceSeparated(); + + do { + // Handle leading <custom-ident>*. + if (m_valueList->current()->unit == CSSParserValue::ValueList) { + if (trailingIdentWasAdded) { + // A row's trailing ident must be concatenated with the next row's leading one. + parseGridLineNames(*m_valueList, *templateRows, downcast<CSSGridLineNamesValue>(templateRows->item(templateRows->length() - 1))); + } else + parseGridLineNames(*m_valueList, *templateRows); + } + + // Handle a template-area's row. + if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount)) return false; + ++rowCount; + + // Handle template-rows's track-size. + if (m_valueList->current() && m_valueList->current()->unit != CSSParserValue::ValueList && m_valueList->current()->unit != CSSPrimitiveValue::CSS_STRING) { + RefPtr<CSSValue> value = parseGridTrackSize(*m_valueList); + if (!value) + return false; + templateRows->append(value.releaseNonNull()); + } else + templateRows->append(CSSValuePool::singleton().createIdentifierValue(CSSValueAuto)); + + // This will handle the trailing/leading <custom-ident>* in the grammar. + trailingIdentWasAdded = false; + if (m_valueList->current() && m_valueList->current()->unit == CSSParserValue::ValueList) + trailingIdentWasAdded = parseGridLineNames(*m_valueList, *templateRows); + } while (m_valueList->current()); + + // [<track-list> /]? + if (templateColumns) + addProperty(CSSPropertyWebkitGridTemplateColumns, templateColumns, important); + else + addProperty(CSSPropertyWebkitGridTemplateColumns, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important); + + // [<line-names>? <string> [<track-size> <line-names>]? ]+ + RefPtr<CSSValue> templateAreas = CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount); + addProperty(CSSPropertyWebkitGridTemplateAreas, templateAreas.release(), important); + addProperty(CSSPropertyWebkitGridTemplateRows, templateRows.release(), important); + + return true; +} + +bool CSSParser::parseGridTemplateShorthand(bool important) +{ + ShorthandScope scope(this, CSSPropertyWebkitGridTemplate); + ASSERT(shorthandForProperty(CSSPropertyWebkitGridTemplate).length() == 3); + + // At least "none" must be defined. + if (!m_valueList->current()) + return false; + + bool firstValueIsNone = m_valueList->current()->id == CSSValueNone; - addProperty(propId, cssValuePool().createIdentifierValue(value->id), important); + // 1- 'none' case. + if (firstValueIsNone && !m_valueList->next()) { + addProperty(CSSPropertyWebkitGridTemplateColumns, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important); + addProperty(CSSPropertyWebkitGridTemplateRows, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important); + addProperty(CSSPropertyWebkitGridTemplateAreas, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important); return true; } - RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated(); - while (m_valueList->current()) { - RefPtr<CSSPrimitiveValue> primitiveValue = parseGridTrackSize(); - if (!primitiveValue) + unsigned index = 0; + RefPtr<CSSValue> columnsValue = firstValueIsNone ? CSSValuePool::singleton().createIdentifierValue(CSSValueNone) : parseGridTrackList(); + + // 2- <grid-template-columns> / <grid-template-columns> syntax. + if (columnsValue) { + if (!(m_valueList->current() && isForwardSlashOperator(*m_valueList->current()) && m_valueList->next())) return false; + index = m_valueList->currentIndex(); + if (RefPtr<CSSValue> rowsValue = parseGridTrackList()) { + if (m_valueList->current()) + return false; + addProperty(CSSPropertyWebkitGridTemplateColumns, columnsValue.release(), important); + addProperty(CSSPropertyWebkitGridTemplateRows, rowsValue.release(), important); + addProperty(CSSPropertyWebkitGridTemplateAreas, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important); + return true; + } + } + + + // 3- [<track-list> /]? [<line-names>? <string> [<track-size> <line-names>]? ]+ syntax. + // The template-columns <track-list> can't be 'none'. + if (firstValueIsNone) + return false; + // It requires to rewind parsing due to previous syntax failures. + m_valueList->setCurrentIndex(index); + return parseGridTemplateRowsAndAreas(columnsValue, important); +} - values->append(primitiveValue.release()); +bool CSSParser::parseGridShorthand(bool important) +{ + ShorthandScope scope(this, CSSPropertyWebkitGrid); + ASSERT(shorthandForProperty(CSSPropertyWebkitGrid).length() == 8); + + // 1- <grid-template> + if (parseGridTemplateShorthand(important)) { + // It can only be specified the explicit or the implicit grid properties in a single grid declaration. + // The sub-properties not specified are set to their initial value, as normal for shorthands. + addProperty(CSSPropertyWebkitGridAutoFlow, CSSValuePool::singleton().createImplicitInitialValue(), important); + addProperty(CSSPropertyWebkitGridAutoColumns, CSSValuePool::singleton().createImplicitInitialValue(), important); + addProperty(CSSPropertyWebkitGridAutoRows, CSSValuePool::singleton().createImplicitInitialValue(), important); + addProperty(CSSPropertyWebkitGridColumnGap, CSSValuePool::singleton().createImplicitInitialValue(), important); + addProperty(CSSPropertyWebkitGridRowGap, CSSValuePool::singleton().createImplicitInitialValue(), important); + return true; } - addProperty(propId, values.release(), important); + + // Need to rewind parsing to explore the alternative syntax of this shorthand. + m_valueList->setCurrentIndex(0); + + // 2- <grid-auto-flow> [ <grid-auto-columns> [ / <grid-auto-rows> ]? ] + if (!parseValue(CSSPropertyWebkitGridAutoFlow, important)) + return false; + + RefPtr<CSSValue> autoColumnsValue; + RefPtr<CSSValue> autoRowsValue; + + if (m_valueList->current()) { + autoColumnsValue = parseGridTrackSize(*m_valueList); + if (!autoColumnsValue) + return false; + if (m_valueList->current()) { + if (!isForwardSlashOperator(*m_valueList->current()) || !m_valueList->next()) + return false; + autoRowsValue = parseGridTrackSize(*m_valueList); + if (!autoRowsValue) + return false; + } + if (m_valueList->current()) + return false; + } else { + // Other omitted values are set to their initial values. + autoColumnsValue = CSSValuePool::singleton().createImplicitInitialValue(); + autoRowsValue = CSSValuePool::singleton().createImplicitInitialValue(); + } + + // if <grid-auto-rows> value is omitted, it is set to the value specified for grid-auto-columns. + if (!autoRowsValue) + autoRowsValue = autoColumnsValue; + + addProperty(CSSPropertyWebkitGridAutoColumns, autoColumnsValue.release(), important); + addProperty(CSSPropertyWebkitGridAutoRows, autoRowsValue.release(), important); + + // It can only be specified the explicit or the implicit grid properties in a single grid declaration. + // The sub-properties not specified are set to their initial value, as normal for shorthands. + addProperty(CSSPropertyWebkitGridTemplateColumns, CSSValuePool::singleton().createImplicitInitialValue(), important); + addProperty(CSSPropertyWebkitGridTemplateRows, CSSValuePool::singleton().createImplicitInitialValue(), important); + addProperty(CSSPropertyWebkitGridTemplateAreas, CSSValuePool::singleton().createImplicitInitialValue(), important); + addProperty(CSSPropertyWebkitGridColumnGap, CSSValuePool::singleton().createImplicitInitialValue(), important); + addProperty(CSSPropertyWebkitGridRowGap, CSSValuePool::singleton().createImplicitInitialValue(), important); + return true; } -PassRefPtr<CSSPrimitiveValue> CSSParser::parseGridTrackSize() +bool CSSParser::parseGridAreaShorthand(bool important) { - CSSParserValue* currentValue = m_valueList->current(); + ShorthandScope scope(this, CSSPropertyWebkitGridArea); + ASSERT(shorthandForProperty(CSSPropertyWebkitGridArea).length() == 4); + + RefPtr<CSSValue> rowStartValue = parseGridPosition(); + if (!rowStartValue) + return false; + + RefPtr<CSSValue> columnStartValue; + if (!parseSingleGridAreaLonghand(columnStartValue)) + return false; + + RefPtr<CSSValue> rowEndValue; + if (!parseSingleGridAreaLonghand(rowEndValue)) + return false; + + RefPtr<CSSValue> columnEndValue; + if (!parseSingleGridAreaLonghand(columnEndValue)) + return false; + + if (!columnStartValue) + columnStartValue = gridMissingGridPositionValue(*rowStartValue); + + if (!rowEndValue) + rowEndValue = gridMissingGridPositionValue(*rowStartValue); + + if (!columnEndValue) + columnEndValue = gridMissingGridPositionValue(*columnStartValue); + + addProperty(CSSPropertyWebkitGridRowStart, rowStartValue, important); + addProperty(CSSPropertyWebkitGridColumnStart, columnStartValue, important); + addProperty(CSSPropertyWebkitGridRowEnd, rowEndValue, important); + addProperty(CSSPropertyWebkitGridColumnEnd, columnEndValue, important); + return true; +} + +bool CSSParser::parseSingleGridAreaLonghand(RefPtr<CSSValue>& property) +{ + if (!m_valueList->current()) + return true; + + if (!isForwardSlashOperator(*m_valueList->current())) + return false; + + if (!m_valueList->next()) + return false; + + property = parseGridPosition(); + return true; +} + +bool CSSParser::parseGridLineNames(CSSParserValueList& inputList, CSSValueList& valueList, CSSGridLineNamesValue* previousNamedAreaTrailingLineNames) +{ + ASSERT(inputList.current() && inputList.current()->unit == CSSParserValue::ValueList); + + CSSParserValueList& identList = *inputList.current()->valueList; + if (!identList.size()) { + inputList.next(); + return false; + } + + // Need to ensure the identList is at the heading index, since the parserList might have been rewound. + identList.setCurrentIndex(0); + RefPtr<CSSGridLineNamesValue> lineNames; + if (previousNamedAreaTrailingLineNames) + lineNames = previousNamedAreaTrailingLineNames; + else + lineNames = CSSGridLineNamesValue::create(); + while (CSSParserValue* identValue = identList.current()) { + ASSERT(identValue->unit == CSSPrimitiveValue::CSS_IDENT); + lineNames->append(createPrimitiveStringValue(*identValue)); + identList.next(); + } + if (!previousNamedAreaTrailingLineNames) + valueList.append(lineNames.releaseNonNull()); + + inputList.next(); + return true; +} + +RefPtr<CSSValue> CSSParser::parseGridTrackList() +{ + CSSParserValue* value = m_valueList->current(); + if (value->id == CSSValueNone) { + m_valueList->next(); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); + } + + RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated(); + // Handle leading <custom-ident>*. + value = m_valueList->current(); + if (value && value->unit == CSSParserValue::ValueList) + parseGridLineNames(*m_valueList, *values); + + bool seenTrackSizeOrRepeatFunction = false; + while (CSSParserValue* currentValue = m_valueList->current()) { + if (isForwardSlashOperator(*currentValue)) + break; + if (currentValue->unit == CSSParserValue::Function && equalLettersIgnoringASCIICase(currentValue->function->name, "repeat(")) { + if (!parseGridTrackRepeatFunction(*values)) + return nullptr; + } else { + RefPtr<CSSValue> value = parseGridTrackSize(*m_valueList); + if (!value) + return nullptr; + values->append(value.releaseNonNull()); + } + seenTrackSizeOrRepeatFunction = true; + + // This will handle the trailing <custom-ident>* in the grammar. + value = m_valueList->current(); + if (value && value->unit == CSSParserValue::ValueList) + parseGridLineNames(*m_valueList, *values); + } + + if (!seenTrackSizeOrRepeatFunction) + return nullptr; + + return values; +} + +bool CSSParser::parseGridTrackRepeatFunction(CSSValueList& list) +{ + CSSParserValueList* arguments = m_valueList->current()->function->args.get(); + if (!arguments || arguments->size() < 3) + return false; + + ValueWithCalculation firstValueWithCalculation(*arguments->valueAt(0)); + if (!validateUnit(firstValueWithCalculation, FPositiveInteger) || !isComma(arguments->valueAt(1))) + return false; + + // If arguments->valueAt(0)->fValue > SIZE_MAX then repetitions becomes 0 during the type casting, that's why we + // clamp it down to kGridMaxTracks before the type casting. + unsigned repetitions = clampTo<unsigned>(parsedDouble(firstValueWithCalculation), 0, kGridMaxTracks); + + RefPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated(); + arguments->next(); // Skip the repetition count. + arguments->next(); // Skip the comma. + + // Handle leading <custom-ident>*. + CSSParserValue* currentValue = arguments->current(); + if (currentValue && currentValue->unit == CSSParserValue::ValueList) + parseGridLineNames(*arguments, *repeatedValues); + + unsigned numberOfTracks = 0; + while (arguments->current()) { + RefPtr<CSSValue> trackSize = parseGridTrackSize(*arguments); + if (!trackSize) + return false; + + repeatedValues->append(trackSize.releaseNonNull()); + ++numberOfTracks; + + // This takes care of any trailing <custom-ident>* in the grammar. + currentValue = arguments->current(); + if (currentValue && currentValue->unit == CSSParserValue::ValueList) + parseGridLineNames(*arguments, *repeatedValues); + } + + // We should have found at least one <track-size>, otherwise the declaration is invalid. + if (!numberOfTracks) + return false; + + // We clamp the number of repetitions to a multiple of the repeat() track list's size, while staying below the max + // grid size. + repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks); + + for (size_t i = 0; i < repetitions; ++i) { + for (size_t j = 0; j < repeatedValues->length(); ++j) + list.append(*repeatedValues->itemWithoutBoundsCheck(j)); + } + m_valueList->next(); + return true; +} - if (currentValue->id == CSSValueAuto) - return cssValuePool().createIdentifierValue(CSSValueAuto); +RefPtr<CSSValue> CSSParser::parseGridTrackSize(CSSParserValueList& inputList) +{ + CSSParserValue& currentValue = *inputList.current(); + inputList.next(); + + if (currentValue.id == CSSValueAuto) + return CSSValuePool::singleton().createIdentifierValue(CSSValueAuto); - if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax(")) { + if (currentValue.unit == CSSParserValue::Function && equalLettersIgnoringASCIICase(currentValue.function->name, "minmax(")) { // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> ) - CSSParserValueList* arguments = currentValue->function->args.get(); + CSSParserValueList* arguments = currentValue.function->args.get(); if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1))) - return 0; + return nullptr; - RefPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0)); + RefPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(*arguments->valueAt(0)); if (!minTrackBreadth) - return 0; + return nullptr; - RefPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2)); + RefPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(*arguments->valueAt(2)); if (!maxTrackBreadth) - return 0; + return nullptr; + + RefPtr<CSSValueList> parsedArguments = CSSValueList::createCommaSeparated(); + parsedArguments->append(minTrackBreadth.releaseNonNull()); + parsedArguments->append(maxTrackBreadth.releaseNonNull()); + return CSSFunctionValue::create("minmax(", parsedArguments); + } - return createPrimitiveValuePair(minTrackBreadth, maxTrackBreadth); + return parseGridBreadth(currentValue); +} + +RefPtr<CSSPrimitiveValue> CSSParser::parseGridBreadth(CSSParserValue& value) +{ + if (value.id == CSSValueWebkitMinContent || value.id == CSSValueWebkitMaxContent || value.id == CSSValueAuto) + return CSSValuePool::singleton().createIdentifierValue(value.id); + + if (value.unit == CSSPrimitiveValue::CSS_FR) { + double flexValue = value.fValue; + + // Fractional unit is a non-negative dimension. + if (flexValue <= 0) + return nullptr; + + return CSSValuePool::singleton().createValue(flexValue, CSSPrimitiveValue::CSS_FR); } - if (PassRefPtr<CSSPrimitiveValue> trackBreadth = parseGridBreadth(currentValue)) - return trackBreadth; + ValueWithCalculation valueWithCalculation(value); + if (!validateUnit(valueWithCalculation, FNonNeg | FLength | FPercent)) + return nullptr; - return 0; + return createPrimitiveNumericValue(valueWithCalculation); } -PassRefPtr<CSSPrimitiveValue> CSSParser::parseGridBreadth(CSSParserValue* currentValue) +static inline bool isValidGridAutoFlowId(CSSValueID id) { - if (currentValue->id == CSSValueWebkitMinContent || currentValue->id == CSSValueWebkitMaxContent) - return cssValuePool().createIdentifierValue(currentValue->id); + return (id == CSSValueRow || id == CSSValueColumn || id == CSSValueDense); +} - if (!validUnit(currentValue, FLength | FPercent)) - return 0; +RefPtr<CSSValue> CSSParser::parseGridAutoFlow(CSSParserValueList& inputList) +{ + // [ row | column ] || dense + CSSParserValue* value = inputList.current(); + if (!value) + return nullptr; + + RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated(); + + // First parameter. + CSSValueID firstId = value->id; + if (!isValidGridAutoFlowId(firstId)) + return nullptr; + + // Second parameter, if any. + // If second parameter is not valid we should process anyway the first one as we can be inside the "grid" shorthand. + value = inputList.next(); + if (!value || !isValidGridAutoFlowId(value->id)) { + if (firstId == CSSValueDense) + parsedValues->append(CSSValuePool::singleton().createIdentifierValue(CSSValueRow)); - return createPrimitiveNumericValue(currentValue); + parsedValues->append(CSSValuePool::singleton().createIdentifierValue(firstId)); + return parsedValues; + } + + switch (firstId) { + case CSSValueRow: + case CSSValueColumn: + parsedValues->append(CSSValuePool::singleton().createIdentifierValue(firstId)); + if (value->id == CSSValueDense) { + parsedValues->append(CSSValuePool::singleton().createIdentifierValue(value->id)); + inputList.next(); + } + break; + case CSSValueDense: + if (value->id == CSSValueRow || value->id == CSSValueColumn) { + parsedValues->append(CSSValuePool::singleton().createIdentifierValue(value->id)); + inputList.next(); + } + parsedValues->append(CSSValuePool::singleton().createIdentifierValue(firstId)); + break; + default: + ASSERT_NOT_REACHED(); + break; + } + + return parsedValues; } +#endif /* ENABLE(CSS_GRID_LAYOUT) */ #if ENABLE(DASHBOARD_SUPPORT) @@ -4849,8 +6026,8 @@ static CSSParserValue* skipCommaInDashboardRegion(CSSParserValueList *args) { if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) || args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) { - CSSParserValue* current = args->current(); - if (current->unit == CSSParserValue::Operator && current->iValue == ',') + CSSParserValue& current = *args->current(); + if (current.unit == CSSParserValue::Operator && current.iValue == ',') return args->next(); } return args->current(); @@ -4865,20 +6042,20 @@ bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important) if (value->id == CSSValueNone) { if (m_valueList->next()) return false; - addProperty(propId, cssValuePool().createIdentifierValue(value->id), important); + addProperty(propId, CSSValuePool::singleton().createIdentifierValue(value->id), important); return valid; } - RefPtr<DashboardRegion> firstRegion = DashboardRegion::create(); - DashboardRegion* region = 0; + auto firstRegion = DashboardRegion::create(); + DashboardRegion* region = nullptr; while (value) { - if (region == 0) { - region = firstRegion.get(); + if (!region) { + region = firstRegion.ptr(); } else { - RefPtr<DashboardRegion> nextRegion = DashboardRegion::create(); - region->m_next = nextRegion; - region = nextRegion.get(); + auto nextRegion = DashboardRegion::create(); + region->m_next = nextRegion.copyRef(); + region = nextRegion.ptr(); } if (value->unit != CSSParserValue::Function) { @@ -4893,7 +6070,7 @@ bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important) // dashboard-region(label, type) or dashboard-region(label type) // dashboard-region(label, type) or dashboard-region(label type) CSSParserValueList* args = value->function->args.get(); - if (!equalIgnoringCase(value->function->name, "dashboard-region(") || !args) { + if (!equalLettersIgnoringASCIICase(value->function->name, "dashboard-region(") || !args) { valid = false; break; } @@ -4922,9 +6099,9 @@ bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important) break; } - if (equalIgnoringCase(arg, "circle")) + if (equalLettersIgnoringASCIICase(*arg, "circle")) region->m_isCircle = true; - else if (equalIgnoringCase(arg, "rectangle")) + else if (equalLettersIgnoringASCIICase(*arg, "rectangle")) region->m_isRectangle = true; else { valid = false; @@ -4935,7 +6112,7 @@ bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important) if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) { // This originally used CSSValueInvalid by accident. It might be more logical to use something else. - RefPtr<CSSPrimitiveValue> amount = cssValuePool().createIdentifierValue(CSSValueInvalid); + RefPtr<CSSPrimitiveValue> amount = CSSValuePool::singleton().createIdentifierValue(CSSValueInvalid); region->setTop(amount); region->setRight(amount); @@ -4943,18 +6120,16 @@ bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important) region->setLeft(amount); } else { // Next four arguments must be offset numbers - int i; - for (i = 0; i < 4; i++) { + for (int i = 0; i < 4; ++i) { arg = args->next(); arg = skipCommaInDashboardRegion(args); - valid = arg->id == CSSValueAuto || validUnit(arg, FLength); + ValueWithCalculation argWithCalculation(*arg); + valid = arg->id == CSSValueAuto || validateUnit(argWithCalculation, FLength); if (!valid) break; - RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ? - cssValuePool().createIdentifierValue(CSSValueAuto) : - createPrimitiveNumericValue(arg); + RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ? CSSValuePool::singleton().createIdentifierValue(CSSValueAuto) : createPrimitiveNumericValue(argWithCalculation); if (i == 0) region->setTop(amount); @@ -4974,87 +6149,202 @@ bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important) } if (valid) - addProperty(propId, cssValuePool().createValue(firstRegion.release()), important); + addProperty(propId, CSSValuePool::singleton().createValue(RefPtr<DashboardRegion>(WTFMove(firstRegion))), important); return valid; } #endif /* ENABLE(DASHBOARD_SUPPORT) */ -PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters) +#if ENABLE(CSS_GRID_LAYOUT) +static Vector<String> parseGridTemplateAreasColumnNames(const String& gridRowNames) +{ + ASSERT(!gridRowNames.isEmpty()); + Vector<String> columnNames; + // Using StringImpl to avoid checks and indirection in every call to String::operator[]. + StringImpl& text = *gridRowNames.impl(); + unsigned length = text.length(); + unsigned index = 0; + while (index < length) { + if (text[index] != ' ' && text[index] != '.') { + unsigned gridAreaStart = index; + while (index < length && text[index] != ' ' && text[index] != '.') + index++; + columnNames.append(text.substring(gridAreaStart, index - gridAreaStart)); + continue; + } + + if (text[index] == '.') { + while (index < length && text[index] == '.') + index++; + columnNames.append("."); + continue; + } + + index++; + } + + return columnNames; +} + +bool CSSParser::parseGridTemplateAreasRow(NamedGridAreaMap& gridAreaMap, const unsigned rowCount, unsigned& columnCount) +{ + CSSParserValue* currentValue = m_valueList->current(); + if (!currentValue || currentValue->unit != CSSPrimitiveValue::CSS_STRING) + return false; + + String gridRowNames = currentValue->string; + if (gridRowNames.containsOnlyWhitespace()) + return false; + + Vector<String> columnNames = parseGridTemplateAreasColumnNames(gridRowNames); + if (!columnCount) { + columnCount = columnNames.size(); + ASSERT(columnCount); + } else if (columnCount != columnNames.size()) { + // The declaration is invalid is all the rows don't have the number of columns. + return false; + } + + for (unsigned currentColumn = 0; currentColumn < columnCount; ++currentColumn) { + const String& gridAreaName = columnNames[currentColumn]; + + // Unamed areas are always valid (we consider them to be 1x1). + if (gridAreaName == ".") + continue; + + // We handle several grid areas with the same name at once to simplify the validation code. + unsigned lookAheadColumn; + for (lookAheadColumn = currentColumn + 1; lookAheadColumn < columnCount; ++lookAheadColumn) { + if (columnNames[lookAheadColumn] != gridAreaName) + break; + } + + auto gridAreaIterator = gridAreaMap.find(gridAreaName); + if (gridAreaIterator == gridAreaMap.end()) + gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan::definiteGridSpan(rowCount, rowCount + 1), GridSpan::definiteGridSpan(currentColumn, lookAheadColumn))); + else { + GridCoordinate& gridCoordinate = gridAreaIterator->value; + + // The following checks test that the grid area is a single filled-in rectangle. + // 1. The new row is adjacent to the previously parsed row. + if (rowCount != gridCoordinate.rows.resolvedFinalPosition().toInt()) + return false; + + // 2. The new area starts at the same position as the previously parsed area. + if (currentColumn != gridCoordinate.columns.resolvedInitialPosition().toInt()) + return false; + + // 3. The new area ends at the same position as the previously parsed area. + if (lookAheadColumn != gridCoordinate.columns.resolvedFinalPosition().toInt()) + return false; + + gridCoordinate.rows = GridSpan::definiteGridSpan(gridCoordinate.rows.resolvedInitialPosition(), gridCoordinate.rows.resolvedFinalPosition().next()); + } + currentColumn = lookAheadColumn - 1; + } + + m_valueList->next(); + return true; +} + +RefPtr<CSSValue> CSSParser::parseGridTemplateAreas() +{ + if (m_valueList->current() && m_valueList->current()->id == CSSValueNone) { + m_valueList->next(); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); + } + + NamedGridAreaMap gridAreaMap; + unsigned rowCount = 0; + unsigned columnCount = 0; + + while (m_valueList->current()) { + if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount)) + return nullptr; + ++rowCount; + } + + if (!rowCount || !columnCount) + return nullptr; + + return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount); +} +#endif /* ENABLE(CSS_GRID_LAYOUT) */ + +RefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList& args, bool counters) { - unsigned numArgs = args->size(); + unsigned numArgs = args.size(); if (counters && numArgs != 3 && numArgs != 5) - return 0; + return nullptr; if (!counters && numArgs != 1 && numArgs != 3) - return 0; + return nullptr; - CSSParserValue* i = args->current(); - if (i->unit != CSSPrimitiveValue::CSS_IDENT) - return 0; - RefPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i); + CSSParserValue* argument = args.current(); + if (argument->unit != CSSPrimitiveValue::CSS_IDENT) + return nullptr; + RefPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(*argument); RefPtr<CSSPrimitiveValue> separator; if (!counters) - separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING); + separator = CSSValuePool::singleton().createValue(String(), CSSPrimitiveValue::CSS_STRING); else { - i = args->next(); - if (i->unit != CSSParserValue::Operator || i->iValue != ',') - return 0; + argument = args.next(); + if (argument->unit != CSSParserValue::Operator || argument->iValue != ',') + return nullptr; - i = args->next(); - if (i->unit != CSSPrimitiveValue::CSS_STRING) - return 0; + argument = args.next(); + if (argument->unit != CSSPrimitiveValue::CSS_STRING) + return nullptr; - separator = createPrimitiveStringValue(i); + separator = createPrimitiveStringValue(*argument); } RefPtr<CSSPrimitiveValue> listStyle; - i = args->next(); - if (!i) // Make the list style default decimal - listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal); + argument = args.next(); + if (!argument) // Make the list style default decimal + listStyle = CSSValuePool::singleton().createIdentifierValue(CSSValueDecimal); else { - if (i->unit != CSSParserValue::Operator || i->iValue != ',') - return 0; + if (argument->unit != CSSParserValue::Operator || argument->iValue != ',') + return nullptr; - i = args->next(); - if (i->unit != CSSPrimitiveValue::CSS_IDENT) - return 0; + argument = args.next(); + if (argument->unit != CSSPrimitiveValue::CSS_IDENT) + return nullptr; CSSValueID listStyleID = CSSValueInvalid; - if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha)) - listStyleID = i->id; + if (argument->id == CSSValueNone || (argument->id >= CSSValueDisc && argument->id <= CSSValueKatakanaIroha)) + listStyleID = argument->id; else - return 0; + return nullptr; - listStyle = cssValuePool().createIdentifierValue(listStyleID); + listStyle = CSSValuePool::singleton().createIdentifierValue(listStyleID); } - return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release())); + return CSSValuePool::singleton().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release())); } bool CSSParser::parseClipShape(CSSPropertyID propId, bool important) { - CSSParserValue* value = m_valueList->current(); - CSSParserValueList* args = value->function->args.get(); + CSSParserValue& value = *m_valueList->current(); + CSSParserValueList* args = value.function->args.get(); - if (!equalIgnoringCase(value->function->name, "rect(") || !args) + if (!equalLettersIgnoringASCIICase(value.function->name, "rect(") || !args) return false; // rect(t, r, b, l) || rect(t r b l) if (args->size() != 4 && args->size() != 7) return false; - RefPtr<Rect> rect = Rect::create(); + auto rect = Rect::create(); bool valid = true; int i = 0; - CSSParserValue* a = args->current(); - while (a) { - valid = a->id == CSSValueAuto || validUnit(a, FLength); + CSSParserValue* argument = args->current(); + while (argument) { + ValueWithCalculation argumentWithCalculation(*argument); + valid = argument->id == CSSValueAuto || validateUnit(argumentWithCalculation, FLength); if (!valid) break; - RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ? - cssValuePool().createIdentifierValue(CSSValueAuto) : - createPrimitiveNumericValue(a); + RefPtr<CSSPrimitiveValue> length = argument->id == CSSValueAuto ? CSSValuePool::singleton().createIdentifierValue(CSSValueAuto) : createPrimitiveNumericValue(argumentWithCalculation); if (i == 0) rect->setTop(length); else if (i == 1) @@ -5063,10 +6353,10 @@ bool CSSParser::parseClipShape(CSSPropertyID propId, bool important) rect->setBottom(length); else rect->setLeft(length); - a = args->next(); - if (a && args->size() == 7) { - if (a->unit == CSSParserValue::Operator && a->iValue == ',') { - a = args->next(); + argument = args->next(); + if (argument && args->size() == 7) { + if (argument->unit == CSSParserValue::Operator && argument->iValue == ',') { + argument = args->next(); } else { valid = false; break; @@ -5075,304 +6365,440 @@ bool CSSParser::parseClipShape(CSSPropertyID propId, bool important) i++; } if (valid) { - addProperty(propId, cssValuePool().createValue(rect.release()), important); + addProperty(propId, CSSValuePool::singleton().createValue(WTFMove(rect)), important); m_valueList->next(); return true; } return false; } -PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeRectangle(CSSParserValueList* args) +static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4]) { - ASSERT(args); + if (radii[3]) + return; + if (!radii[2]) { + if (!radii[1]) + radii[1] = radii[0]; + radii[2] = radii[0]; + } + radii[3] = radii[1]; +} - // rect(x, y, width, height, [[rx], ry]) - if (args->size() != 7 && args->size() != 9 && args->size() != 11) - return 0; +// FIXME: This should be refactored with CSSParser::parseBorderRadius. +// CSSParser::parseBorderRadius contains support for some legacy radius construction. +RefPtr<CSSBasicShape> CSSParser::parseInsetRoundedCorners(PassRefPtr<CSSBasicShapeInset> shape, CSSParserValueList& args) +{ + CSSParserValue* argument = args.next(); - RefPtr<CSSBasicShapeRectangle> shape = CSSBasicShapeRectangle::create(); + if (!argument) + return nullptr; - unsigned argumentNumber = 0; - CSSParserValue* argument = args->current(); + Vector<CSSParserValue*> radiusArguments; while (argument) { - Units unitFlags = FLength | FPercent; - if (argumentNumber > 1) { - // Arguments width, height, rx, and ry cannot be negative. - unitFlags = unitFlags | FNonNeg; - } - if (!validUnit(argument, unitFlags)) - return 0; - - RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument); - ASSERT(argumentNumber < 6); - switch (argumentNumber) { - case 0: - shape->setX(length); - break; - case 1: - shape->setY(length); - break; - case 2: - shape->setWidth(length); - break; - case 3: - shape->setHeight(length); - break; - case 4: - shape->setRadiusX(length); - break; - case 5: - shape->setRadiusY(length); - break; - } - argument = args->next(); - if (argument) { - if (!isComma(argument)) - return 0; + radiusArguments.append(argument); + argument = args.next(); + } - argument = args->next(); + unsigned num = radiusArguments.size(); + if (!num || num > 9) + return nullptr; + + RefPtr<CSSPrimitiveValue> radii[2][4]; + + unsigned indexAfterSlash = 0; + for (unsigned i = 0; i < num; ++i) { + CSSParserValue& value = *radiusArguments.at(i); + if (value.unit == CSSParserValue::Operator) { + if (value.iValue != '/') + return nullptr; + + if (!i || indexAfterSlash || i + 1 == num || num > i + 5) + return nullptr; + + indexAfterSlash = i + 1; + completeBorderRadii(radii[0]); + continue; } - argumentNumber++; + + if (i - indexAfterSlash >= 4) + return nullptr; + + ValueWithCalculation valueWithCalculation(value); + if (!validateUnit(valueWithCalculation, FLength | FPercent | FNonNeg)) + return nullptr; + + RefPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(valueWithCalculation); + + if (!indexAfterSlash) + radii[0][i] = radius; + else + radii[1][i - indexAfterSlash] = radius.release(); } - if (argumentNumber < 4) - return 0; + if (!indexAfterSlash) { + completeBorderRadii(radii[0]); + for (unsigned i = 0; i < 4; ++i) + radii[1][i] = radii[0][i]; + } else + completeBorderRadii(radii[1]); + + shape->setTopLeftRadius(createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release())); + shape->setTopRightRadius(createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release())); + shape->setBottomRightRadius(createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release())); + shape->setBottomLeftRadius(createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release())); + return shape; } -PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeInsetRectangle(CSSParserValueList* args) +RefPtr<CSSBasicShape> CSSParser::parseBasicShapeInset(CSSParserValueList& args) { - ASSERT(args); + RefPtr<CSSBasicShapeInset> shape = CSSBasicShapeInset::create(); - // inset-rectangle(top, right, bottom, left, [[rx], ry]) - if (args->size() != 7 && args->size() != 9 && args->size() != 11) - return 0; - - RefPtr<CSSBasicShapeInsetRectangle> shape = CSSBasicShapeInsetRectangle::create(); - - unsigned argumentNumber = 0; - CSSParserValue* argument = args->current(); + CSSParserValue* argument = args.current(); + Vector<RefPtr<CSSPrimitiveValue> > widthArguments; + bool hasRoundedInset = false; while (argument) { - Units unitFlags = FLength | FPercent | FNonNeg; - if (!validUnit(argument, unitFlags)) - return 0; - - RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument); - ASSERT(argumentNumber < 6); - switch (argumentNumber) { - case 0: - shape->setTop(length); - break; - case 1: - shape->setRight(length); - break; - case 2: - shape->setBottom(length); - break; - case 3: - shape->setLeft(length); - break; - case 4: - shape->setRadiusX(length); - break; - case 5: - shape->setRadiusY(length); + if (argument->unit == CSSPrimitiveValue::CSS_IDENT && equalLettersIgnoringASCIICase(argument->string, "round")) { + hasRoundedInset = true; break; } - argument = args->next(); - if (argument) { - if (!isComma(argument)) - return 0; - argument = args->next(); + Units unitFlags = FLength | FPercent; + ValueWithCalculation argumentWithCalculation(*argument); + if (!validateUnit(argumentWithCalculation, unitFlags) || widthArguments.size() > 4) + return nullptr; + + widthArguments.append(createPrimitiveNumericValue(argumentWithCalculation)); + argument = args.next(); + } + + switch (widthArguments.size()) { + case 1: { + shape->updateShapeSize1Value(widthArguments[0].get()); + break; + } + case 2: { + shape->updateShapeSize2Values(widthArguments[0].get(), widthArguments[1].get()); + break; } - argumentNumber++; + case 3: { + shape->updateShapeSize3Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get()); + break; + } + case 4: { + shape->updateShapeSize4Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get(), widthArguments[3].get()); + break; + } + default: + return nullptr; } - if (argumentNumber < 4) - return 0; + if (hasRoundedInset) + return parseInsetRoundedCorners(shape, args); return shape; } -PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeCircle(CSSParserValueList* args) +RefPtr<CSSPrimitiveValue> CSSParser::parseShapeRadius(CSSParserValue& value) { - ASSERT(args); + if (value.id == CSSValueClosestSide || value.id == CSSValueFarthestSide) + return CSSValuePool::singleton().createIdentifierValue(value.id); - // circle(centerX, centerY, radius) - if (args->size() != 5) - return 0; + ValueWithCalculation valueWithCalculation(value); + if (!validateUnit(valueWithCalculation, FLength | FPercent | FNonNeg)) + return nullptr; + + return createPrimitiveNumericValue(valueWithCalculation); +} +RefPtr<CSSBasicShape> CSSParser::parseBasicShapeCircle(CSSParserValueList& args) +{ + // circle(radius) + // circle(radius at <position>) + // circle(at <position>) + // where position defines centerX and centerY using a CSS <position> data type. RefPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create(); - unsigned argumentNumber = 0; - CSSParserValue* argument = args->current(); - while (argument) { - Units unitFlags = FLength | FPercent; - if (argumentNumber == 2) { - // Argument radius cannot be negative. - unitFlags = unitFlags | FNonNeg; - } + for (CSSParserValue* argument = args.current(); argument; argument = args.next()) { + // The call to parseFillPosition below should consume all of the + // arguments except the first two. Thus, and index greater than one + // indicates an invalid production. + if (args.currentIndex() > 1) + return nullptr; - if (!validUnit(argument, unitFlags)) - return 0; + if (!args.currentIndex() && argument->id != CSSValueAt) { + if (RefPtr<CSSPrimitiveValue> radius = parseShapeRadius(*argument)) { + shape->setRadius(radius); + continue; + } - RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument); - ASSERT(argumentNumber < 3); - switch (argumentNumber) { - case 0: - shape->setCenterX(length); - break; - case 1: - shape->setCenterY(length); - break; - case 2: - shape->setRadius(length); - break; + return nullptr; } - argument = args->next(); - if (argument) { - if (!isComma(argument)) - return 0; - argument = args->next(); - } - argumentNumber++; + if (argument->id == CSSValueAt && args.next()) { + RefPtr<CSSPrimitiveValue> centerX; + RefPtr<CSSPrimitiveValue> centerY; + parseFillPosition(args, centerX, centerY); + if (centerX && centerY && !args.current()) { + shape->setCenterX(centerX); + shape->setCenterY(centerY); + } else + return nullptr; + } else + return nullptr; } - if (argumentNumber < 3) - return 0; return shape; } -PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeEllipse(CSSParserValueList* args) +RefPtr<CSSBasicShape> CSSParser::parseBasicShapeEllipse(CSSParserValueList& args) { - ASSERT(args); + // ellipse(radiusX) + // ellipse(radiusX at <position>) + // ellipse(radiusX radiusY) + // ellipse(radiusX radiusY at <position>) + // ellipse(at <position>) + // where position defines centerX and centerY using a CSS <position> data type. + RefPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create(); - // ellipse(centerX, centerY, radiusX, radiusY) - if (args->size() != 7) - return 0; + for (CSSParserValue* argument = args.current(); argument; argument = args.next()) { + // The call to parseFillPosition below should consume all of the + // arguments except the first three. Thus, an index greater than two + // indicates an invalid production. + if (args.currentIndex() > 2) + return nullptr; + + if (args.currentIndex() < 2 && argument->id != CSSValueAt) { + if (RefPtr<CSSPrimitiveValue> radius = parseShapeRadius(*argument)) { + if (!shape->radiusX()) + shape->setRadiusX(radius); + else + shape->setRadiusY(radius); + continue; + } - RefPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create(); - unsigned argumentNumber = 0; - CSSParserValue* argument = args->current(); - while (argument) { - Units unitFlags = FLength | FPercent; - if (argumentNumber > 1) { - // Arguments radiusX and radiusY cannot be negative. - unitFlags = unitFlags | FNonNeg; - } - if (!validUnit(argument, unitFlags)) - return 0; - - RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument); - ASSERT(argumentNumber < 4); - switch (argumentNumber) { - case 0: - shape->setCenterX(length); - break; - case 1: - shape->setCenterY(length); - break; - case 2: - shape->setRadiusX(length); - break; - case 3: - shape->setRadiusY(length); - break; + return nullptr; } - argument = args->next(); - if (argument) { - if (!isComma(argument)) - return 0; - argument = args->next(); - } - argumentNumber++; + if (argument->id != CSSValueAt || !args.next()) // expecting ellipse(.. at <position>) + return nullptr; + + RefPtr<CSSPrimitiveValue> centerX; + RefPtr<CSSPrimitiveValue> centerY; + parseFillPosition(args, centerX, centerY); + if (!centerX || !centerY || args.current()) + return nullptr; + + shape->setCenterX(centerX); + shape->setCenterY(centerY); } - if (argumentNumber < 4) - return 0; return shape; } -PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapePolygon(CSSParserValueList* args) +RefPtr<CSSBasicShape> CSSParser::parseBasicShapePolygon(CSSParserValueList& args) { - ASSERT(args); - - unsigned size = args->size(); + unsigned size = args.size(); if (!size) - return 0; + return nullptr; RefPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create(); - CSSParserValue* argument = args->current(); + CSSParserValue* argument = args.current(); if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) { shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO); - if (!isComma(args->next())) - return 0; + if (!isComma(args.next())) + return nullptr; - argument = args->next(); + argument = args.next(); size -= 2; } // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one if (!size || (size % 3) - 2) - return 0; + return nullptr; CSSParserValue* argumentX = argument; while (argumentX) { - if (!validUnit(argumentX, FLength | FPercent)) - return 0; - CSSParserValue* argumentY = args->next(); - if (!argumentY || !validUnit(argumentY, FLength | FPercent)) - return 0; + ValueWithCalculation argumentXWithCalculation(*argumentX); + if (!validateUnit(argumentXWithCalculation, FLength | FPercent)) + return nullptr; + RefPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentXWithCalculation); - RefPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX); - RefPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY); + CSSParserValue* argumentY = args.next(); + if (!argumentY) + return nullptr; + ValueWithCalculation argumentYWithCalculation(*argumentY); + if (!validateUnit(argumentYWithCalculation, FLength | FPercent)) + return nullptr; + RefPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentYWithCalculation); shape->appendPoint(xLength.release(), yLength.release()); - CSSParserValue* commaOrNull = args->next(); + CSSParserValue* commaOrNull = args.next(); if (!commaOrNull) - argumentX = 0; + argumentX = nullptr; else if (!isComma(commaOrNull)) - return 0; + return nullptr; else - argumentX = args->next(); + argumentX = args.next(); } return shape; } -bool CSSParser::parseBasicShape(CSSPropertyID propId, bool important) +RefPtr<CSSBasicShape> CSSParser::parseBasicShapePath(CSSParserValueList& args) +{ + unsigned size = args.size(); + if (size != 1 && size != 3) + return nullptr; + + WindRule windRule = RULE_NONZERO; + + CSSParserValue* argument = args.current(); + if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) { + windRule = argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO; + + if (!isComma(args.next())) + return nullptr; + argument = args.next(); + } + + if (argument->unit != CSSPrimitiveValue::CSS_STRING) + return nullptr; + + auto byteStream = std::make_unique<SVGPathByteStream>(); + if (!buildSVGPathByteStreamFromString(argument->string, *byteStream, UnalteredParsing)) + return nullptr; + + RefPtr<CSSBasicShapePath> shape = CSSBasicShapePath::create(WTFMove(byteStream)); + shape->setWindRule(windRule); + + args.next(); + return shape; +} + +static bool isBoxValue(CSSValueID valueId, CSSPropertyID propId) +{ + switch (valueId) { + case CSSValueContentBox: + case CSSValuePaddingBox: + case CSSValueBorderBox: + case CSSValueMarginBox: + return true; + case CSSValueFill: + case CSSValueStroke: + case CSSValueViewBox: + return propId == CSSPropertyWebkitClipPath; + default: break; + } + + return false; +} + +RefPtr<CSSValue> CSSParser::parseBasicShapeAndOrBox(CSSPropertyID propId) { CSSParserValue* value = m_valueList->current(); - ASSERT(value->unit == CSSParserValue::Function); - CSSParserValueList* args = value->function->args.get(); + + bool shapeFound = false; + bool boxFound = false; + CSSValueID valueId; + + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + for (unsigned i = 0; i < 2; ++i) { + if (!value) + break; + valueId = value->id; + if (value->unit == CSSParserValue::Function && !shapeFound) { + // parseBasicShape already asks for the next value list item. + RefPtr<CSSPrimitiveValue> shapeValue = parseBasicShape(); + if (!shapeValue) + return nullptr; + list->append(shapeValue.releaseNonNull()); + shapeFound = true; + } else if (isBoxValue(valueId, propId) && !boxFound) { + RefPtr<CSSPrimitiveValue> parsedValue = CSSValuePool::singleton().createIdentifierValue(valueId); + list->append(parsedValue.releaseNonNull()); + boxFound = true; + m_valueList->next(); + } else + return nullptr; + value = m_valueList->current(); + } + + if (m_valueList->current()) + return nullptr; + return list; +} + +#if ENABLE(CSS_SHAPES) +RefPtr<CSSValue> CSSParser::parseShapeProperty(CSSPropertyID propId) +{ + if (!RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled()) + return nullptr; + + CSSParserValue& value = *m_valueList->current(); + CSSValueID valueId = value.id; + + if (valueId == CSSValueNone) { + m_valueList->next(); + return CSSValuePool::singleton().createIdentifierValue(valueId); + } + + RefPtr<CSSValue> imageValue; + if (valueId != CSSValueNone && parseFillImage(*m_valueList, imageValue)) { + m_valueList->next(); + return imageValue; + } + + return parseBasicShapeAndOrBox(propId); +} +#endif + +RefPtr<CSSValue> CSSParser::parseClipPath() +{ + CSSParserValue& value = *m_valueList->current(); + CSSValueID valueId = value.id; + + if (valueId == CSSValueNone) { + m_valueList->next(); + return CSSValuePool::singleton().createIdentifierValue(valueId); + } + if (value.unit == CSSPrimitiveValue::CSS_URI) { + m_valueList->next(); + return CSSPrimitiveValue::create(value.string, CSSPrimitiveValue::CSS_URI); + } + + return parseBasicShapeAndOrBox(CSSPropertyWebkitClipPath); +} + +RefPtr<CSSPrimitiveValue> CSSParser::parseBasicShape() +{ + CSSParserValue& value = *m_valueList->current(); + ASSERT(value.unit == CSSParserValue::Function); + CSSParserValueList* args = value.function->args.get(); if (!args) - return false; + return nullptr; RefPtr<CSSBasicShape> shape; - if (equalIgnoringCase(value->function->name, "rectangle(")) - shape = parseBasicShapeRectangle(args); - else if (equalIgnoringCase(value->function->name, "circle(")) - shape = parseBasicShapeCircle(args); - else if (equalIgnoringCase(value->function->name, "ellipse(")) - shape = parseBasicShapeEllipse(args); - else if (equalIgnoringCase(value->function->name, "polygon(")) - shape = parseBasicShapePolygon(args); - else if (equalIgnoringCase(value->function->name, "inset-rectangle(")) - shape = parseBasicShapeInsetRectangle(args); + if (equalLettersIgnoringASCIICase(value.function->name, "circle(")) + shape = parseBasicShapeCircle(*args); + else if (equalLettersIgnoringASCIICase(value.function->name, "ellipse(")) + shape = parseBasicShapeEllipse(*args); + else if (equalLettersIgnoringASCIICase(value.function->name, "polygon(")) + shape = parseBasicShapePolygon(*args); + else if (equalLettersIgnoringASCIICase(value.function->name, "path(")) + shape = parseBasicShapePath(*args); + else if (equalLettersIgnoringASCIICase(value.function->name, "inset(")) + shape = parseBasicShapeInset(*args); if (!shape) - return false; + return nullptr; - addProperty(propId, cssValuePool().createValue(shape.release()), important); m_valueList->next(); - return true; + return CSSValuePool::singleton().createValue(shape.releaseNonNull()); } // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family' @@ -5391,12 +6817,12 @@ bool CSSParser::parseFont(bool important) bool fontWeightParsed = false; CSSParserValue* value; while ((value = m_valueList->current())) { - if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) { - addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important); + if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context, m_styleSheet)) { + addProperty(CSSPropertyFontStyle, CSSValuePool::singleton().createIdentifierValue(value->id), important); fontStyleParsed = true; } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) { // Font variant in the shorthand is particular, it only accepts normal or small-caps. - addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important); + addProperty(CSSPropertyFontVariantCaps, CSSValuePool::singleton().createIdentifierValue(value->id), important); fontVariantParsed = true; } else if (!fontWeightParsed && parseFontWeight(important)) fontWeightParsed = true; @@ -5409,11 +6835,11 @@ bool CSSParser::parseFont(bool important) return false; if (!fontStyleParsed) - addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true); + addProperty(CSSPropertyFontStyle, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important, true); if (!fontVariantParsed) - addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true); + addProperty(CSSPropertyFontVariantCaps, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important, true); if (!fontWeightParsed) - addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true); + addProperty(CSSPropertyFontWeight, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important, true); // Now a font size _must_ come. // <absolute-size> | <relative-size> | <length> | <percentage> | inherit @@ -5424,7 +6850,7 @@ bool CSSParser::parseFont(bool important) if (!value) return false; - if (isForwardSlashOperator(value)) { + if (isForwardSlashOperator(*value)) { // The line-height property. value = m_valueList->next(); if (!value) @@ -5432,7 +6858,7 @@ bool CSSParser::parseFont(bool important) if (!parseLineHeight(important)) return false; } else - addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true); + addProperty(CSSPropertyLineHeight, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important, true); // Font family must come now. RefPtr<CSSValue> parsedFamilyValue = parseFontFamily(); @@ -5450,9 +6876,33 @@ bool CSSParser::parseFont(bool important) return true; } +void CSSParser::parseSystemFont(bool important) +{ + ASSERT(m_valueList->size() == 1); + CSSValueID systemFontID = m_valueList->valueAt(0)->id; + ASSERT(systemFontID >= CSSValueCaption && systemFontID <= CSSValueStatusBar); + m_valueList->next(); + + FontCascadeDescription fontDescription; + RenderTheme::defaultTheme()->systemFont(systemFontID, fontDescription); + if (!fontDescription.isAbsoluteSize()) + return; + + // We must set font's constituent properties, even for system fonts, so the cascade functions correctly. + ShorthandScope scope(this, CSSPropertyFont); + addProperty(CSSPropertyFontStyle, CSSValuePool::singleton().createIdentifierValue(fontDescription.italic() == FontItalicOn ? CSSValueItalic : CSSValueNormal), important); + addProperty(CSSPropertyFontWeight, CSSValuePool::singleton().createValue(fontDescription.weight()), important); + addProperty(CSSPropertyFontSize, CSSValuePool::singleton().createValue(fontDescription.specifiedSize(), CSSPrimitiveValue::CSS_PX), important); + Ref<CSSValueList> fontFamilyList = CSSValueList::createCommaSeparated(); + fontFamilyList->append(CSSValuePool::singleton().createFontFamilyValue(fontDescription.familyAt(0), FromSystemFontID::Yes)); + addProperty(CSSPropertyFontFamily, WTFMove(fontFamilyList), important); + addProperty(CSSPropertyFontVariantCaps, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important); + addProperty(CSSPropertyLineHeight, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important); +} + class FontFamilyValueBuilder { public: - FontFamilyValueBuilder(CSSValueList* list) + FontFamilyValueBuilder(CSSValueList& list) : m_list(list) { } @@ -5474,21 +6924,27 @@ public: { if (m_builder.isEmpty()) return; - m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString())); + m_list.append(CSSValuePool::singleton().createFontFamilyValue(m_builder.toString())); m_builder.clear(); } private: StringBuilder m_builder; - CSSValueList* m_list; + CSSValueList& m_list; }; -PassRefPtr<CSSValueList> CSSParser::parseFontFamily() +static bool valueIsCSSKeyword(const CSSParserValue& value) +{ + // FIXME: when we add "unset", we should handle it here. + return value.id == CSSValueInitial || value.id == CSSValueInherit || value.id == CSSValueDefault; +} + +RefPtr<CSSValueList> CSSParser::parseFontFamily() { RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); CSSParserValue* value = m_valueList->current(); - FontFamilyValueBuilder familyBuilder(list.get()); + FontFamilyValueBuilder familyBuilder(*list); bool inFamily = false; while (value) { @@ -5499,7 +6955,7 @@ PassRefPtr<CSSValueList> CSSParser::parseFontFamily() ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) || (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT)); - bool valueIsKeyword = value->id == CSSValueInitial || value->id == CSSValueInherit || value->id == CSSValueDefault; + bool valueIsKeyword = valueIsCSSKeyword(*value); if (valueIsKeyword && !inFamily) { if (nextValBreaksFont) value = m_valueList->next(); @@ -5512,7 +6968,7 @@ PassRefPtr<CSSValueList> CSSParser::parseFontFamily() if (inFamily) familyBuilder.add(value->string); else if (nextValBreaksFont || !nextValIsFontName) - list->append(cssValuePool().createIdentifierValue(value->id)); + list->append(CSSValuePool::singleton().createIdentifierValue(value->id)); else { familyBuilder.commit(); familyBuilder.add(value->string); @@ -5522,12 +6978,12 @@ PassRefPtr<CSSValueList> CSSParser::parseFontFamily() // Strings never share in a family name. inFamily = false; familyBuilder.commit(); - list->append(cssValuePool().createFontFamilyValue(value->string)); + list->append(CSSValuePool::singleton().createFontFamilyValue(value->string)); } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) { if (inFamily) familyBuilder.add(value->string); else if (nextValBreaksFont || !nextValIsFontName) - list->append(cssValuePool().createFontFamilyValue(value->string)); + list->append(CSSValuePool::singleton().createFontFamilyValue(value->string)); else { familyBuilder.commit(); familyBuilder.add(value->string); @@ -5553,87 +7009,40 @@ PassRefPtr<CSSValueList> CSSParser::parseFontFamily() familyBuilder.commit(); if (!list->length()) - list = 0; - return list.release(); + list = nullptr; + return list; } bool CSSParser::parseLineHeight(bool important) { - CSSParserValue* value = m_valueList->current(); - CSSValueID id = value->id; + ValueWithCalculation valueWithCalculation(*m_valueList->current()); + CSSValueID id = valueWithCalculation.value().id; bool validPrimitive = false; // normal | <number> | <length> | <percentage> | inherit if (id == CSSValueNormal) validPrimitive = true; else - validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg)); + validPrimitive = (!id && validateUnit(valueWithCalculation, FNumber | FLength | FPercent | FNonNeg)); if (validPrimitive && (!m_valueList->next() || inShorthand())) - addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important); + addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, valueWithCalculation), important); return validPrimitive; } bool CSSParser::parseFontSize(bool important) { - CSSParserValue* value = m_valueList->current(); - CSSValueID id = value->id; + ValueWithCalculation valueWithCalculation(*m_valueList->current()); + CSSValueID id = valueWithCalculation.value().id; bool validPrimitive = false; // <absolute-size> | <relative-size> | <length> | <percentage> | inherit if (id >= CSSValueXxSmall && id <= CSSValueLarger) validPrimitive = true; else - validPrimitive = validUnit(value, FLength | FPercent | FNonNeg); + validPrimitive = validateUnit(valueWithCalculation, FLength | FPercent | FNonNeg); if (validPrimitive && (!m_valueList->next() || inShorthand())) - addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important); + addProperty(CSSPropertyFontSize, parseValidPrimitive(id, valueWithCalculation), important); return validPrimitive; } -bool CSSParser::parseFontVariant(bool important) -{ - RefPtr<CSSValueList> values; - if (m_valueList->size() > 1) - values = CSSValueList::createCommaSeparated(); - CSSParserValue* val; - bool expectComma = false; - while ((val = m_valueList->current())) { - RefPtr<CSSPrimitiveValue> parsedValue; - if (!expectComma) { - expectComma = true; - if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps) - parsedValue = cssValuePool().createIdentifierValue(val->id); - else if (val->id == CSSValueAll && !values) { - // 'all' is only allowed in @font-face and with no other values. Make a value list to - // indicate that we are in the @font-face case. - values = CSSValueList::createCommaSeparated(); - parsedValue = cssValuePool().createIdentifierValue(val->id); - } - } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') { - expectComma = false; - m_valueList->next(); - continue; - } - - if (!parsedValue) - return false; - - m_valueList->next(); - - if (values) - values->append(parsedValue.release()); - else { - addProperty(CSSPropertyFontVariant, parsedValue.release(), important); - return true; - } - } - - if (values && values->length()) { - m_hasFontFaceOnlyValues = true; - addProperty(CSSPropertyFontVariant, values.release(), important); - return true; - } - - return false; -} - static CSSValueID createFontWeightValueKeyword(int weight) { ASSERT(!(weight % 100) && weight >= 100 && weight <= 900); @@ -5644,37 +7053,73 @@ static CSSValueID createFontWeightValueKeyword(int weight) bool CSSParser::parseFontWeight(bool important) { - CSSParserValue* value = m_valueList->current(); - if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) { - addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important); + CSSParserValue& value = *m_valueList->current(); + if ((value.id >= CSSValueNormal) && (value.id <= CSSValue900)) { + addProperty(CSSPropertyFontWeight, CSSValuePool::singleton().createIdentifierValue(value.id), important); return true; } - if (validUnit(value, FInteger | FNonNeg, CSSQuirksMode)) { - int weight = static_cast<int>(value->fValue); + ValueWithCalculation valueWithCalculation(value); + if (validateUnit(valueWithCalculation, FInteger | FNonNeg, CSSQuirksMode)) { + int weight = static_cast<int>(parsedDouble(valueWithCalculation)); if (!(weight % 100) && weight >= 100 && weight <= 900) { - addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(createFontWeightValueKeyword(weight)), important); + addProperty(CSSPropertyFontWeight, CSSValuePool::singleton().createIdentifierValue(createFontWeightValueKeyword(weight)), important); return true; } } return false; } -bool CSSParser::parseFontFaceSrcURI(CSSValueList* valueList) +bool CSSParser::parseFontSynthesis(bool important) +{ + // none | [ weight || style ] + CSSParserValue* value = m_valueList->current(); + if (value && value->id == CSSValueNone) { + addProperty(CSSPropertyFontSynthesis, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important); + m_valueList->next(); + return true; + } + + bool encounteredWeight = false; + bool encounteredStyle = false; + while (value) { + switch (value->id) { + case CSSValueWeight: + encounteredWeight = true; + break; + case CSSValueStyle: + encounteredStyle = true; + break; + default: + return false; + } + value = m_valueList->next(); + } + + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + if (encounteredWeight) + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueWeight)); + if (encounteredStyle) + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueStyle)); + addProperty(CSSPropertyFontSynthesis, list.release(), important); + return true; +} + +bool CSSParser::parseFontFaceSrcURI(CSSValueList& valueList) { RefPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string))); CSSParserValue* value = m_valueList->next(); if (!value) { - valueList->append(uriValue.release()); + valueList.append(uriValue.releaseNonNull()); return true; } if (value->unit == CSSParserValue::Operator && value->iValue == ',') { m_valueList->next(); - valueList->append(uriValue.release()); + valueList.append(uriValue.releaseNonNull()); return true; } - if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format(")) + if (value->unit != CSSParserValue::Function || !equalLettersIgnoringASCIICase(value->function->name, "format(")) return false; // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings, @@ -5683,21 +7128,21 @@ bool CSSParser::parseFontFaceSrcURI(CSSValueList* valueList) if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT)) return false; uriValue->setFormat(args->current()->string); - valueList->append(uriValue.release()); + valueList.append(uriValue.releaseNonNull()); value = m_valueList->next(); if (value && value->unit == CSSParserValue::Operator && value->iValue == ',') m_valueList->next(); return true; } -bool CSSParser::parseFontFaceSrcLocal(CSSValueList* valueList) +bool CSSParser::parseFontFaceSrcLocal(CSSValueList& valueList) { CSSParserValueList* args = m_valueList->current()->function->args.get(); if (!args || !args->size()) return false; if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING) - valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string)); + valueList.append(CSSFontFaceSrcValue::createLocal(args->current()->string)); else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) { StringBuilder builder; for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) { @@ -5707,7 +7152,7 @@ bool CSSParser::parseFontFaceSrcLocal(CSSValueList* valueList) builder.append(' '); builder.append(localValue->string); } - valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString())); + valueList.append(CSSFontFaceSrcValue::createLocal(builder.toString())); } else return false; @@ -5724,10 +7169,10 @@ bool CSSParser::parseFontFaceSrc() while (CSSParserValue* value = m_valueList->current()) { if (value->unit == CSSPrimitiveValue::CSS_URI) { - if (!parseFontFaceSrcURI(values.get())) + if (!parseFontFaceSrcURI(*values)) return false; - } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) { - if (!parseFontFaceSrcLocal(values.get())) + } else if (value->unit == CSSParserValue::Function && equalLettersIgnoringASCIICase(value->function->name, "local(")) { + if (!parseFontFaceSrcLocal(*values)) return false; } else return false; @@ -6145,83 +7590,78 @@ bool CSSParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict) return false; } -inline double CSSParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc) +inline double CSSParser::parsedDouble(ValueWithCalculation& valueWithCalculation) { - const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue; - if (releaseCalc == ReleaseParsedCalcValue) - m_parsedCalculation.release(); - return result; + return valueWithCalculation.calculation() ? valueWithCalculation.calculation()->doubleValue() : valueWithCalculation.value().fValue; } -bool CSSParser::isCalculation(CSSParserValue* value) +bool CSSParser::isCalculation(CSSParserValue& value) { - return (value->unit == CSSParserValue::Function) - && (equalIgnoringCase(value->function->name, "calc(") - || equalIgnoringCase(value->function->name, "-webkit-calc(") - || equalIgnoringCase(value->function->name, "-webkit-min(") - || equalIgnoringCase(value->function->name, "-webkit-max(")); + return value.unit == CSSParserValue::Function + && (equalLettersIgnoringASCIICase(value.function->name, "calc(") + || equalLettersIgnoringASCIICase(value.function->name, "-webkit-calc(")); } -inline int CSSParser::colorIntFromValue(CSSParserValue* v) +inline int CSSParser::colorIntFromValue(ValueWithCalculation& valueWithCalculation) { bool isPercent; - if (m_parsedCalculation) - isPercent = m_parsedCalculation->category() == CalcPercent; + if (valueWithCalculation.calculation()) + isPercent = valueWithCalculation.calculation()->category() == CalcPercent; else - isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE; + isPercent = valueWithCalculation.value().unit == CSSPrimitiveValue::CSS_PERCENTAGE; - const double value = parsedDouble(v, ReleaseParsedCalcValue); + const double doubleValue = parsedDouble(valueWithCalculation); - if (value <= 0.0) + if (doubleValue <= 0.0) return 0; if (isPercent) { - if (value >= 100.0) + if (doubleValue >= 100.0) return 255; - return static_cast<int>(value * 256.0 / 100.0); + return static_cast<int>(doubleValue * 256.0 / 100.0); } - if (value >= 255.0) + if (doubleValue >= 255.0) return 255; - return static_cast<int>(value); + return static_cast<int>(doubleValue); } -bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha) +bool CSSParser::parseColorParameters(CSSParserValue& value, int* colorArray, bool parseAlpha) { - CSSParserValueList* args = value->function->args.get(); - CSSParserValue* v = args->current(); + CSSParserValueList* args = value.function->args.get(); + ValueWithCalculation firstArgumentWithCalculation(*args->current()); Units unitType = FUnknown; // Get the first value and its type - if (validUnit(v, FInteger, CSSStrictMode)) + if (validateUnit(firstArgumentWithCalculation, FInteger, CSSStrictMode)) unitType = FInteger; - else if (validUnit(v, FPercent, CSSStrictMode)) + else if (validateUnit(firstArgumentWithCalculation, FPercent, CSSStrictMode)) unitType = FPercent; else return false; - colorArray[0] = colorIntFromValue(v); + colorArray[0] = colorIntFromValue(firstArgumentWithCalculation); for (int i = 1; i < 3; i++) { - v = args->next(); - if (v->unit != CSSParserValue::Operator && v->iValue != ',') + CSSParserValue& operatorArgument = *args->next(); + if (operatorArgument.unit != CSSParserValue::Operator && operatorArgument.iValue != ',') return false; - v = args->next(); - if (!validUnit(v, unitType, CSSStrictMode)) + ValueWithCalculation argumentWithCalculation(*args->next()); + if (!validateUnit(argumentWithCalculation, unitType, CSSStrictMode)) return false; - colorArray[i] = colorIntFromValue(v); + colorArray[i] = colorIntFromValue(argumentWithCalculation); } if (parseAlpha) { - v = args->next(); - if (v->unit != CSSParserValue::Operator && v->iValue != ',') + CSSParserValue& operatorArgument = *args->next(); + if (operatorArgument.unit != CSSParserValue::Operator && operatorArgument.iValue != ',') return false; - v = args->next(); - if (!validUnit(v, FNumber, CSSStrictMode)) + ValueWithCalculation argumentWithCalculation(*args->next()); + if (!validateUnit(argumentWithCalculation, FNumber, CSSStrictMode)) return false; - const double value = parsedDouble(v, ReleaseParsedCalcValue); + double doubleValue = parsedDouble(argumentWithCalculation); // Convert the floating pointer number of alpha to an integer in the range [0, 256), // with an equal distribution across all 256 values. - colorArray[3] = static_cast<int>(max(0.0, min(1.0, value)) * nextafter(256.0, 0.0)); + colorArray[3] = static_cast<int>(std::max<double>(0, std::min<double>(1, doubleValue)) * nextafter(256.0, 0.0)); } return true; } @@ -6231,86 +7671,86 @@ bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, boo // and with alpha, the format is // hsla(<number>, <percent>, <percent>, <number>) // The first value, HUE, is in an angle with a value between 0 and 360 -bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha) +bool CSSParser::parseHSLParameters(CSSParserValue& value, double* colorArray, bool parseAlpha) { - CSSParserValueList* args = value->function->args.get(); - CSSParserValue* v = args->current(); + CSSParserValueList* args = value.function->args.get(); + ValueWithCalculation firstArgumentWithCalculation(*args->current()); // Get the first value - if (!validUnit(v, FNumber, CSSStrictMode)) + if (!validateUnit(firstArgumentWithCalculation, FNumber, CSSStrictMode)) return false; // normalize the Hue value and change it to be between 0 and 1.0 - colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0; - for (int i = 1; i < 3; i++) { - v = args->next(); - if (v->unit != CSSParserValue::Operator && v->iValue != ',') + colorArray[0] = (((static_cast<int>(parsedDouble(firstArgumentWithCalculation)) % 360) + 360) % 360) / 360.0; + for (int i = 1; i < 3; ++i) { + CSSParserValue& operatorArgument = *args->next(); + if (operatorArgument.unit != CSSParserValue::Operator && operatorArgument.iValue != ',') return false; - v = args->next(); - if (!validUnit(v, FPercent, CSSStrictMode)) + ValueWithCalculation argumentWithCalculation(*args->next()); + if (!validateUnit(argumentWithCalculation, FPercent, CSSStrictMode)) return false; - colorArray[i] = max(0.0, min(100.0, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0 + colorArray[i] = std::max<double>(0, std::min<double>(100, parsedDouble(argumentWithCalculation))) / 100.0; // needs to be value between 0 and 1.0 } if (parseAlpha) { - v = args->next(); - if (v->unit != CSSParserValue::Operator && v->iValue != ',') + CSSParserValue& operatorArgument = *args->next(); + if (operatorArgument.unit != CSSParserValue::Operator && operatorArgument.iValue != ',') return false; - v = args->next(); - if (!validUnit(v, FNumber, CSSStrictMode)) + ValueWithCalculation argumentWithCalculation(*args->next()); + if (!validateUnit(argumentWithCalculation, FNumber, CSSStrictMode)) return false; - colorArray[3] = max(0.0, min(1.0, parsedDouble(v, ReleaseParsedCalcValue))); + colorArray[3] = std::max<double>(0, std::min<double>(1, parsedDouble(argumentWithCalculation))); } return true; } -PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value) +RefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value) { RGBA32 c = Color::transparent; - if (!parseColorFromValue(value ? value : m_valueList->current(), c)) - return 0; - return cssValuePool().createColorValue(c); + if (!parseColorFromValue(value ? *value : *m_valueList->current(), c)) + return nullptr; + return CSSValuePool::singleton().createColorValue(c); } -bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c) +bool CSSParser::parseColorFromValue(CSSParserValue& value, RGBA32& c) { - if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER - && value->fValue >= 0. && value->fValue < 1000000.) { - String str = String::format("%06d", static_cast<int>((value->fValue+.5))); + if (inQuirksMode() && value.unit == CSSPrimitiveValue::CSS_NUMBER + && value.fValue >= 0. && value.fValue < 1000000.) { + String str = String::format("%06d", static_cast<int>((value.fValue+.5))); // FIXME: This should be strict parsing for SVG as well. if (!fastParseColor(c, str, inStrictMode())) return false; - } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR || - value->unit == CSSPrimitiveValue::CSS_IDENT || - (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) { - if (!fastParseColor(c, value->string, inStrictMode() && value->unit == CSSPrimitiveValue::CSS_IDENT)) + } else if (value.unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR + || value.unit == CSSPrimitiveValue::CSS_IDENT + || (inQuirksMode() && value.unit == CSSPrimitiveValue::CSS_DIMENSION)) { + if (!fastParseColor(c, value.string, inStrictMode() && value.unit == CSSPrimitiveValue::CSS_IDENT)) return false; - } else if (value->unit == CSSParserValue::Function && - value->function->args != 0 && - value->function->args->size() == 5 /* rgb + two commas */ && - equalIgnoringCase(value->function->name, "rgb(")) { + } else if (value.unit == CSSParserValue::Function + && value.function->args + && value.function->args->size() == 5 /* rgb + two commas */ + && equalLettersIgnoringASCIICase(value.function->name, "rgb(")) { int colorValues[3]; if (!parseColorParameters(value, colorValues, false)) return false; c = makeRGB(colorValues[0], colorValues[1], colorValues[2]); } else { - if (value->unit == CSSParserValue::Function && - value->function->args != 0 && - value->function->args->size() == 7 /* rgba + three commas */ && - equalIgnoringCase(value->function->name, "rgba(")) { + if (value.unit == CSSParserValue::Function + && value.function->args + && value.function->args->size() == 7 /* rgba + three commas */ + && equalLettersIgnoringASCIICase(value.function->name, "rgba(")) { int colorValues[4]; if (!parseColorParameters(value, colorValues, true)) return false; c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]); - } else if (value->unit == CSSParserValue::Function && - value->function->args != 0 && - value->function->args->size() == 5 /* hsl + two commas */ && - equalIgnoringCase(value->function->name, "hsl(")) { + } else if (value.unit == CSSParserValue::Function + && value.function->args + && value.function->args->size() == 5 /* hsl + two commas */ + && equalLettersIgnoringASCIICase(value.function->name, "hsl(")) { double colorValues[3]; if (!parseHSLParameters(value, colorValues, false)) return false; c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0); - } else if (value->unit == CSSParserValue::Function && - value->function->args != 0 && - value->function->args->size() == 7 /* hsla + three commas */ && - equalIgnoringCase(value->function->name, "hsla(")) { + } else if (value.unit == CSSParserValue::Function + && value.function->args + && value.function->args->size() == 7 /* hsla + three commas */ + && equalLettersIgnoringASCIICase(value.function->name, "hsla(")) { double colorValues[4]; if (!parseHSLParameters(value, colorValues, true)) return false; @@ -6325,7 +7765,7 @@ bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c) // This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return) // without the allowBreak bit being set, then it will clean up all of the objects and destroy them. struct ShadowParseContext { - ShadowParseContext(CSSPropertyID prop, CSSParser* parser) + ShadowParseContext(CSSPropertyID prop, CSSParser& parser) : property(prop) , m_parser(parser) , allowX(true) @@ -6348,16 +7788,16 @@ struct ShadowParseContext { values = CSSValueList::createCommaSeparated(); // Construct the current shadow value and add it to the list. - values->append(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release())); + values->append(CSSShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release())); } // Now reset for the next shadow value. - x = 0; - y = 0; - blur = 0; - spread = 0; - style = 0; - color = 0; + x = nullptr; + y = nullptr; + blur = nullptr; + spread = nullptr; + style = nullptr; + color = nullptr; allowX = true; allowColor = true; @@ -6368,30 +7808,30 @@ struct ShadowParseContext { allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow; } - void commitLength(CSSParserValue* v) + void commitLength(CSSParser::ValueWithCalculation& valueWithCalculation) { - RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v); + RefPtr<CSSPrimitiveValue> primitiveValue = m_parser.createPrimitiveNumericValue(valueWithCalculation); if (allowX) { - x = val.release(); + x = primitiveValue.release(); allowX = false; allowY = true; allowColor = false; allowStyle = false; allowBreak = false; } else if (allowY) { - y = val.release(); + y = primitiveValue.release(); allowY = false; allowBlur = true; allowColor = true; allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow; allowBreak = true; } else if (allowBlur) { - blur = val.release(); + blur = primitiveValue.release(); allowBlur = false; allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow; } else if (allowSpread) { - spread = val.release(); + spread = primitiveValue.release(); allowSpread = false; } } @@ -6410,9 +7850,9 @@ struct ShadowParseContext { } } - void commitStyle(CSSParserValue* v) + void commitStyle(CSSParserValue& value) { - style = cssValuePool().createIdentifierValue(v->id); + style = CSSValuePool::singleton().createIdentifierValue(value.id); allowStyle = false; if (allowX) allowBreak = false; @@ -6424,7 +7864,7 @@ struct ShadowParseContext { } CSSPropertyID property; - CSSParser* m_parser; + CSSParser& m_parser; RefPtr<CSSValueList> values; RefPtr<CSSPrimitiveValue> x; @@ -6443,64 +7883,64 @@ struct ShadowParseContext { bool allowBreak; }; -PassRefPtr<CSSValueList> CSSParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId) +RefPtr<CSSValueList> CSSParser::parseShadow(CSSParserValueList& valueList, CSSPropertyID propId) { - ShadowParseContext context(propId, this); - CSSParserValue* val; - while ((val = valueList->current())) { + ShadowParseContext context(propId, *this); + CSSParserValue* value; + while ((value = valueList.current())) { + ValueWithCalculation valueWithCalculation(*value); // Check for a comma break first. - if (val->unit == CSSParserValue::Operator) { - if (val->iValue != ',' || !context.allowBreak) + if (value->unit == CSSParserValue::Operator) { + if (value->iValue != ',' || !context.allowBreak) { // Other operators aren't legal or we aren't done with the current shadow // value. Treat as invalid. - return 0; -#if ENABLE(SVG) + return nullptr; + } // -webkit-svg-shadow does not support multiple values. if (propId == CSSPropertyWebkitSvgShadow) - return 0; -#endif + return nullptr; // The value is good. Commit it. context.commitValue(); - } else if (validUnit(val, FLength, CSSStrictMode)) { + } else if (validateUnit(valueWithCalculation, FLength, CSSStrictMode)) { // We required a length and didn't get one. Invalid. if (!context.allowLength()) - return 0; + return nullptr; // Blur radius must be non-negative. - if (context.allowBlur && !validUnit(val, FLength | FNonNeg, CSSStrictMode)) - return 0; + if (context.allowBlur && !validateUnit(valueWithCalculation, FLength | FNonNeg, CSSStrictMode)) + return nullptr; // A length is allowed here. Construct the value and add it. - context.commitLength(val); - } else if (val->id == CSSValueInset) { + context.commitLength(valueWithCalculation); + } else if (value->id == CSSValueInset) { if (!context.allowStyle) - return 0; + return nullptr; - context.commitStyle(val); + context.commitStyle(valueWithCalculation); } else { // The only other type of value that's ok is a color value. RefPtr<CSSPrimitiveValue> parsedColor; - bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu - || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode()) - || val->id == CSSValueCurrentcolor); + bool isColor = (isValidSystemColorValue(value->id) || value->id == CSSValueMenu + || (value->id >= CSSValueWebkitFocusRingColor && value->id <= CSSValueWebkitText && inQuirksMode()) + || value->id == CSSValueCurrentcolor); if (isColor) { if (!context.allowColor) - return 0; - parsedColor = cssValuePool().createIdentifierValue(val->id); + return nullptr; + parsedColor = CSSValuePool::singleton().createIdentifierValue(value->id); } if (!parsedColor) // It's not built-in. Try to parse it as a color. - parsedColor = parseColor(val); + parsedColor = parseColor(value); if (!parsedColor || !context.allowColor) - return 0; // This value is not a color or length and is invalid or + return nullptr; // This value is not a color or length and is invalid or // it is a color, but a color isn't allowed at this point. context.commitColor(parsedColor.release()); } - valueList->next(); + valueList.next(); } if (context.allowBreak) { @@ -6509,7 +7949,7 @@ PassRefPtr<CSSValueList> CSSParser::parseShadow(CSSParserValueList* valueList, C return context.values.release(); } - return 0; + return nullptr; } bool CSSParser::parseReflect(CSSPropertyID propId, bool important) @@ -6517,78 +7957,74 @@ bool CSSParser::parseReflect(CSSPropertyID propId, bool important) // box-reflect: <direction> <offset> <mask> // Direction comes first. - CSSParserValue* val = m_valueList->current(); + CSSParserValue* value = m_valueList->current(); RefPtr<CSSPrimitiveValue> direction; -#if ENABLE(CSS_VARIABLES) - if (val->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME) - direction = createPrimitiveVariableNameValue(val); - else -#endif - switch (val->id) { + switch (value->id) { case CSSValueAbove: case CSSValueBelow: case CSSValueLeft: case CSSValueRight: - direction = cssValuePool().createIdentifierValue(val->id); + direction = CSSValuePool::singleton().createIdentifierValue(value->id); break; default: return false; } // The offset comes next. - val = m_valueList->next(); + value = m_valueList->next(); RefPtr<CSSPrimitiveValue> offset; - if (!val) - offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX); + if (!value) + offset = CSSValuePool::singleton().createValue(0, CSSPrimitiveValue::CSS_PX); else { - if (!validUnit(val, FLength | FPercent)) + ValueWithCalculation valueWithCalculation(*value); + if (!validateUnit(valueWithCalculation, FLength | FPercent)) return false; - offset = createPrimitiveNumericValue(val); + offset = createPrimitiveNumericValue(valueWithCalculation); } // Now for the mask. RefPtr<CSSValue> mask; - val = m_valueList->next(); - if (val) { + value = m_valueList->next(); + if (value) { if (!parseBorderImage(propId, mask)) return false; } - RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction.release(), offset.release(), mask.release()); - addProperty(propId, reflectValue.release(), important); + addProperty(propId, CSSReflectValue::create(direction.release(), offset.release(), mask.release()), important); m_valueList->next(); return true; } -bool CSSParser::parseFlex(CSSParserValueList* args, bool important) +bool CSSParser::parseFlex(CSSParserValueList& args, bool important) { - if (!args || !args->size() || args->size() > 3) + if (!args.size() || args.size() > 3) return false; static const double unsetValue = -1; double flexGrow = unsetValue; double flexShrink = unsetValue; RefPtr<CSSPrimitiveValue> flexBasis; - while (CSSParserValue* arg = args->current()) { - if (validUnit(arg, FNumber | FNonNeg)) { + while (CSSParserValue* argument = args.current()) { + ValueWithCalculation argumentWithCalculation(*argument); + if (validateUnit(argumentWithCalculation, FNumber | FNonNeg)) { if (flexGrow == unsetValue) - flexGrow = arg->fValue; + flexGrow = parsedDouble(argumentWithCalculation); else if (flexShrink == unsetValue) - flexShrink = arg->fValue; - else if (!arg->fValue) { + flexShrink = parsedDouble(argumentWithCalculation); + else if (!parsedDouble(argumentWithCalculation)) { // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set. - flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX); + flexBasis = CSSValuePool::singleton().createValue(0, CSSPrimitiveValue::CSS_PX); } else { // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid. return false; } - } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg))) - flexBasis = parseValidPrimitive(arg->id, arg); + } else if (!flexBasis && (argumentWithCalculation.value().id == CSSValueAuto || validateUnit(argumentWithCalculation, FLength | FPercent | FNonNeg))) + flexBasis = parseValidPrimitive(argumentWithCalculation.value().id, argumentWithCalculation); else { // Not a valid arg for flex. return false; } - args->next(); + args.next(); } if (flexGrow == unsetValue) @@ -6596,11 +8032,11 @@ bool CSSParser::parseFlex(CSSParserValueList* args, bool important) if (flexShrink == unsetValue) flexShrink = 1; if (!flexBasis) - flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX); + flexBasis = CSSValuePool::singleton().createValue(0, CSSPrimitiveValue::CSS_PX); - addProperty(CSSPropertyWebkitFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important); - addProperty(CSSPropertyWebkitFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important); - addProperty(CSSPropertyWebkitFlexBasis, flexBasis, important); + addProperty(CSSPropertyFlexGrow, CSSValuePool::singleton().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important); + addProperty(CSSPropertyFlexShrink, CSSValuePool::singleton().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important); + addProperty(CSSPropertyFlexBasis, flexBasis, important); return true; } @@ -6691,7 +8127,7 @@ struct BorderImageParseContext { return createBorderImageValue(m_image, m_imageSlice, m_borderSlice, m_outset, m_repeat); } - void commitBorderImage(CSSParser* parser, bool important) + void commitBorderImage(CSSParser& parser, bool important) { commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important); commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice, important); @@ -6700,12 +8136,12 @@ struct BorderImageParseContext { commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important); } - void commitBorderImageProperty(CSSPropertyID propId, CSSParser* parser, PassRefPtr<CSSValue> value, bool important) + void commitBorderImageProperty(CSSPropertyID propId, CSSParser& parser, PassRefPtr<CSSValue> value, bool important) { if (value) - parser->addProperty(propId, value, important); + parser.addProperty(propId, value, important); else - parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true); + parser.addProperty(propId, CSSValuePool::singleton().createImplicitInitialValue(), important, true); } bool m_canAdvance; @@ -6731,31 +8167,31 @@ bool CSSParser::parseBorderImage(CSSPropertyID propId, RefPtr<CSSValue>& result, { ShorthandScope scope(this, propId); BorderImageParseContext context; - while (CSSParserValue* val = m_valueList->current()) { + while (CSSParserValue* currentValue = m_valueList->current()) { context.setCanAdvance(false); - if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(val)) + if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(*currentValue)) context.commitForwardSlashOperator(); if (!context.canAdvance() && context.allowImage()) { - if (val->unit == CSSPrimitiveValue::CSS_URI) - context.commitImage(CSSImageValue::create(completeURL(val->string))); - else if (isGeneratedImageValue(val)) { + if (currentValue->unit == CSSPrimitiveValue::CSS_URI) + context.commitImage(CSSImageValue::create(completeURL(currentValue->string))); + else if (isGeneratedImageValue(*currentValue)) { RefPtr<CSSValue> value; - if (parseGeneratedImage(m_valueList.get(), value)) + if (parseGeneratedImage(*m_valueList, value)) context.commitImage(value.release()); else return false; #if ENABLE(CSS_IMAGE_SET) - } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) { + } else if (currentValue->unit == CSSParserValue::Function && equalLettersIgnoringASCIICase(currentValue->function->name, "-webkit-image-set(")) { RefPtr<CSSValue> value = parseImageSet(); if (value) context.commitImage(value.release()); else return false; #endif - } else if (val->id == CSSValueNone) - context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone)); + } else if (currentValue->id == CSSValueNone) + context.commitImage(CSSValuePool::singleton().createIdentifierValue(CSSValueNone)); } if (!context.canAdvance() && context.allowImageSlice()) { @@ -6790,7 +8226,7 @@ bool CSSParser::parseBorderImage(CSSPropertyID propId, RefPtr<CSSValue>& result, if (context.allowCommit()) { if (propId == CSSPropertyBorderImage) - context.commitBorderImage(this, important); + context.commitBorderImage(*this, important); else // Need to fully commit as a single value. result = context.commitWebKitBorderImage(); @@ -6813,14 +8249,14 @@ bool CSSParser::parseBorderImageRepeat(RefPtr<CSSValue>& result) if (!val) return false; if (isBorderImageRepeatKeyword(val->id)) - firstValue = cssValuePool().createIdentifierValue(val->id); + firstValue = CSSValuePool::singleton().createIdentifierValue(val->id); else return false; val = m_valueList->next(); if (val) { if (isBorderImageRepeatKeyword(val->id)) - secondValue = cssValuePool().createIdentifierValue(val->id); + secondValue = CSSValuePool::singleton().createIdentifierValue(val->id); else if (!inShorthand()) { // If we're not parsing a shorthand then we are invalid. return false; @@ -6833,13 +8269,13 @@ bool CSSParser::parseBorderImageRepeat(RefPtr<CSSValue>& result) } else secondValue = firstValue; - result = createPrimitiveValuePair(firstValue, secondValue); + result = createPrimitiveValuePair(WTFMove(firstValue), WTFMove(secondValue)); return true; } class BorderImageSliceParseContext { public: - BorderImageSliceParseContext(CSSParser* parser) + BorderImageSliceParseContext(CSSParser& parser) : m_parser(parser) , m_allowNumber(true) , m_allowFill(true) @@ -6852,18 +8288,18 @@ public: bool allowFinalCommit() const { return m_allowFinalCommit; } CSSPrimitiveValue* top() const { return m_top.get(); } - void commitNumber(CSSParserValue* v) + void commitNumber(CSSParser::ValueWithCalculation& valueWithCalculation) { - RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v); + RefPtr<CSSPrimitiveValue> primitiveValue = m_parser.createPrimitiveNumericValue(valueWithCalculation); if (!m_top) - m_top = val; + m_top = primitiveValue.release(); else if (!m_right) - m_right = val; + m_right = primitiveValue.release(); else if (!m_bottom) - m_bottom = val; + m_bottom = primitiveValue.release(); else { ASSERT(!m_left); - m_left = val; + m_left = primitiveValue.release(); } m_allowNumber = !m_left; @@ -6889,18 +8325,18 @@ public: m_left = m_right; // Now build a rect value to hold all four of our primitive values. - RefPtr<Quad> quad = Quad::create(); + auto quad = Quad::create(); quad->setTop(m_top); quad->setRight(m_right); quad->setBottom(m_bottom); quad->setLeft(m_left); // Make our new border image value now. - return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill); + return CSSBorderImageSliceValue::create(CSSValuePool::singleton().createValue(WTFMove(quad)), m_fill); } private: - CSSParser* m_parser; + CSSParser& m_parser; bool m_allowNumber; bool m_allowFill; @@ -6916,13 +8352,14 @@ private: bool CSSParser::parseBorderImageSlice(CSSPropertyID propId, RefPtr<CSSBorderImageSliceValue>& result) { - BorderImageSliceParseContext context(this); - CSSParserValue* val; - while ((val = m_valueList->current())) { + BorderImageSliceParseContext context(*this); + CSSParserValue* value; + while ((value = m_valueList->current())) { + ValueWithCalculation valueWithCalculation(*value); // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet. - if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, CSSStrictMode)) { - context.commitNumber(val); - } else if (context.allowFill() && val->id == CSSValueFill) + if (context.allowNumber() && !isCalculation(valueWithCalculation) && validateUnit(valueWithCalculation, FInteger | FNonNeg | FPercent, CSSStrictMode)) { + context.commitNumber(valueWithCalculation); + } else if (context.allowFill() && value->id == CSSValueFill) context.commitFill(); else if (!inShorthand()) { // If we're not parsing a shorthand then we are invalid. @@ -6953,7 +8390,7 @@ bool CSSParser::parseBorderImageSlice(CSSPropertyID propId, RefPtr<CSSBorderImag class BorderImageQuadParseContext { public: - BorderImageQuadParseContext(CSSParser* parser) + BorderImageQuadParseContext(CSSParser& parser) : m_parser(parser) , m_allowNumber(true) , m_allowFinalCommit(false) @@ -6963,23 +8400,23 @@ public: bool allowFinalCommit() const { return m_allowFinalCommit; } CSSPrimitiveValue* top() const { return m_top.get(); } - void commitNumber(CSSParserValue* v) + void commitNumber(CSSParser::ValueWithCalculation& valueWithCalculation) { - RefPtr<CSSPrimitiveValue> val; - if (v->id == CSSValueAuto) - val = cssValuePool().createIdentifierValue(v->id); + RefPtr<CSSPrimitiveValue> primitiveValue; + if (valueWithCalculation.value().id == CSSValueAuto) + primitiveValue = CSSValuePool::singleton().createIdentifierValue(valueWithCalculation.value().id); else - val = m_parser->createPrimitiveNumericValue(v); + primitiveValue = m_parser.createPrimitiveNumericValue(valueWithCalculation); if (!m_top) - m_top = val; + m_top = primitiveValue.release(); else if (!m_right) - m_right = val; + m_right = primitiveValue.release(); else if (!m_bottom) - m_bottom = val; + m_bottom = primitiveValue.release(); else { ASSERT(!m_left); - m_left = val; + m_left = primitiveValue.release(); } m_allowNumber = !m_left; @@ -7006,18 +8443,18 @@ public: m_left = m_right; // Now build a quad value to hold all four of our primitive values. - RefPtr<Quad> quad = Quad::create(); + auto quad = Quad::create(); quad->setTop(m_top); quad->setRight(m_right); quad->setBottom(m_bottom); quad->setLeft(m_left); // Make our new value now. - return cssValuePool().createValue(quad.release()); + return CSSValuePool::singleton().createValue(WTFMove(quad)); } private: - CSSParser* m_parser; + CSSParser& m_parser; bool m_allowNumber; bool m_allowFinalCommit; @@ -7030,11 +8467,12 @@ private: bool CSSParser::parseBorderImageQuad(Units validUnits, RefPtr<CSSPrimitiveValue>& result) { - BorderImageQuadParseContext context(this); - CSSParserValue* val; - while ((val = m_valueList->current())) { - if (context.allowNumber() && (validUnit(val, validUnits, CSSStrictMode) || val->id == CSSValueAuto)) { - context.commitNumber(val); + BorderImageQuadParseContext context(*this); + CSSParserValue* value; + while ((value = m_valueList->current())) { + ValueWithCalculation valueWithCalculation(*value); + if (context.allowNumber() && (validateUnit(valueWithCalculation, validUnits, CSSStrictMode) || value->id == CSSValueAuto)) { + context.commitNumber(valueWithCalculation); } else if (!inShorthand()) { // If we're not parsing a shorthand then we are invalid. return false; @@ -7064,18 +8502,6 @@ bool CSSParser::parseBorderImageOutset(RefPtr<CSSPrimitiveValue>& result) return parseBorderImageQuad(FLength | FInteger | FNonNeg, result); } -static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4]) -{ - if (radii[3]) - return; - if (!radii[2]) { - if (!radii[1]) - radii[1] = radii[0]; - radii[2] = radii[0]; - } - radii[3] = radii[1]; -} - bool CSSParser::parseBorderRadius(CSSPropertyID propId, bool important) { unsigned num = m_valueList->size(); @@ -7087,9 +8513,9 @@ bool CSSParser::parseBorderRadius(CSSPropertyID propId, bool important) unsigned indexAfterSlash = 0; for (unsigned i = 0; i < num; ++i) { - CSSParserValue* value = m_valueList->valueAt(i); - if (value->unit == CSSParserValue::Operator) { - if (value->iValue != '/') + CSSParserValue& value = *m_valueList->valueAt(i); + if (value.unit == CSSParserValue::Operator) { + if (value.iValue != '/') return false; if (!i || indexAfterSlash || i + 1 == num || num > i + 5) @@ -7103,10 +8529,11 @@ bool CSSParser::parseBorderRadius(CSSPropertyID propId, bool important) if (i - indexAfterSlash >= 4) return false; - if (!validUnit(value, FLength | FPercent | FNonNeg)) + ValueWithCalculation valueWithCalculation(value); + if (!validateUnit(valueWithCalculation, FLength | FPercent | FNonNeg)) return false; - RefPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value); + RefPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(valueWithCalculation); if (!indexAfterSlash) { radii[0][i] = radius; @@ -7127,7 +8554,7 @@ bool CSSParser::parseBorderRadius(CSSPropertyID propId, bool important) } else completeBorderRadii(radii[1]); - ImplicitScope implicitScope(this, PropertyImplicit); + ImplicitScope implicitScope(*this, PropertyImplicit); addProperty(CSSPropertyBorderTopLeftRadius, createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()), important); addProperty(CSSPropertyBorderTopRightRadius, createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()), important); addProperty(CSSPropertyBorderBottomRightRadius, createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()), important); @@ -7138,28 +8565,32 @@ bool CSSParser::parseBorderRadius(CSSPropertyID propId, bool important) bool CSSParser::parseAspectRatio(bool important) { unsigned num = m_valueList->size(); - if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) { - addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(CSSValueNone), important); - return true; + if (num == 1) { + CSSValueID valueId = m_valueList->valueAt(0)->id; + if (valueId == CSSValueAuto || valueId == CSSValueFromDimensions || valueId == CSSValueFromIntrinsic) { + addProperty(CSSPropertyWebkitAspectRatio, CSSValuePool::singleton().createIdentifierValue(valueId), important); + return true; + } } if (num != 3) return false; - CSSParserValue* lvalue = m_valueList->valueAt(0); - CSSParserValue* op = m_valueList->valueAt(1); - CSSParserValue* rvalue = m_valueList->valueAt(2); + CSSParserValue& op = *m_valueList->valueAt(1); if (!isForwardSlashOperator(op)) return false; - if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg)) + ValueWithCalculation lvalueWithCalculation(*m_valueList->valueAt(0)); + ValueWithCalculation rvalueWithCalculation(*m_valueList->valueAt(2)); + if (!validateUnit(lvalueWithCalculation, FNumber | FNonNeg) || !validateUnit(rvalueWithCalculation, FNumber | FNonNeg)) return false; - if (!lvalue->fValue || !rvalue->fValue) + // FIXME: This doesn't handle calculated values. + if (!lvalueWithCalculation.value().fValue || !rvalueWithCalculation.value().fValue) return false; - addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important); + addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalueWithCalculation.value().fValue), narrowPrecisionToFloat(rvalueWithCalculation.value().fValue)), important); return true; } @@ -7172,11 +8603,11 @@ bool CSSParser::parseCounter(CSSPropertyID propId, int defaultValue, bool import RefPtr<CSSPrimitiveValue> counterName; while (true) { - CSSParserValue* val = m_valueList->current(); + CSSParserValue* value = m_valueList->current(); switch (state) { case ID: - if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) { - counterName = createPrimitiveStringValue(val); + if (value && value->unit == CSSPrimitiveValue::CSS_IDENT) { + counterName = createPrimitiveStringValue(*value); state = VAL; m_valueList->next(); continue; @@ -7184,13 +8615,13 @@ bool CSSParser::parseCounter(CSSPropertyID propId, int defaultValue, bool import break; case VAL: { int i = defaultValue; - if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) { - i = clampToInteger(val->fValue); + if (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) { + i = clampToInteger(value->fValue); m_valueList->next(); } list->append(createPrimitiveValuePair(counterName.release(), - cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER))); + CSSValuePool::singleton().createValue(i, CSSPrimitiveValue::CSS_NUMBER))); state = ID; continue; } @@ -7207,67 +8638,67 @@ bool CSSParser::parseCounter(CSSPropertyID propId, int defaultValue, bool import } // This should go away once we drop support for -webkit-gradient -static PassRefPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal) +static PassRefPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue& value, bool horizontal) { RefPtr<CSSPrimitiveValue> result; - if (a->unit == CSSPrimitiveValue::CSS_IDENT) { - if ((equalIgnoringCase(a, "left") && horizontal) - || (equalIgnoringCase(a, "top") && !horizontal)) - result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE); - else if ((equalIgnoringCase(a, "right") && horizontal) - || (equalIgnoringCase(a, "bottom") && !horizontal)) - result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE); - else if (equalIgnoringCase(a, "center")) - result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE); - } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE) - result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(a->unit)); + if (value.unit == CSSPrimitiveValue::CSS_IDENT) { + if ((equalLettersIgnoringASCIICase(value, "left") && horizontal) + || (equalLettersIgnoringASCIICase(value, "top") && !horizontal)) + result = CSSValuePool::singleton().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE); + else if ((equalLettersIgnoringASCIICase(value, "right") && horizontal) + || (equalLettersIgnoringASCIICase(value, "bottom") && !horizontal)) + result = CSSValuePool::singleton().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE); + else if (equalLettersIgnoringASCIICase(value, "center")) + result = CSSValuePool::singleton().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE); + } else if (value.unit == CSSPrimitiveValue::CSS_NUMBER || value.unit == CSSPrimitiveValue::CSS_PERCENTAGE) + result = CSSValuePool::singleton().createValue(value.fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value.unit)); return result; } -static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop) +static bool parseDeprecatedGradientColorStop(CSSParser& parser, CSSParserValue& value, CSSGradientColorStop& stop) { - if (a->unit != CSSParserValue::Function) + if (value.unit != CSSParserValue::Function) return false; - if (!equalIgnoringCase(a->function->name, "from(") && - !equalIgnoringCase(a->function->name, "to(") && - !equalIgnoringCase(a->function->name, "color-stop(")) + if (!equalLettersIgnoringASCIICase(value.function->name, "from(") + && !equalLettersIgnoringASCIICase(value.function->name, "to(") + && !equalLettersIgnoringASCIICase(value.function->name, "color-stop(")) return false; - CSSParserValueList* args = a->function->args.get(); + CSSParserValueList* args = value.function->args.get(); if (!args) return false; - if (equalIgnoringCase(a->function->name, "from(") - || equalIgnoringCase(a->function->name, "to(")) { + if (equalLettersIgnoringASCIICase(value.function->name, "from(") + || equalLettersIgnoringASCIICase(value.function->name, "to(")) { // The "from" and "to" stops expect 1 argument. if (args->size() != 1) return false; - if (equalIgnoringCase(a->function->name, "from(")) - stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER); + if (equalLettersIgnoringASCIICase(value.function->name, "from(")) + stop.m_position = CSSValuePool::singleton().createValue(0, CSSPrimitiveValue::CSS_NUMBER); else - stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER); + stop.m_position = CSSValuePool::singleton().createValue(1, CSSPrimitiveValue::CSS_NUMBER); CSSValueID id = args->current()->id; - if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu) - stop.m_color = cssValuePool().createIdentifierValue(id); + if (id == CSSValueWebkitText || CSSParser::isValidSystemColorValue(id) || id == CSSValueMenu) + stop.m_color = CSSValuePool::singleton().createIdentifierValue(id); else - stop.m_color = p->parseColor(args->current()); + stop.m_color = parser.parseColor(args->current()); if (!stop.m_color) return false; } // The "color-stop" function expects 3 arguments. - if (equalIgnoringCase(a->function->name, "color-stop(")) { + if (equalLettersIgnoringASCIICase(value.function->name, "color-stop(")) { if (args->size() != 3) return false; CSSParserValue* stopArg = args->current(); if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE) - stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER); + stop.m_position = CSSValuePool::singleton().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER); else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER) - stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER); + stop.m_position = CSSValuePool::singleton().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER); else return false; @@ -7277,10 +8708,10 @@ static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CS stopArg = args->next(); CSSValueID id = stopArg->id; - if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu) - stop.m_color = cssValuePool().createIdentifierValue(id); + if (id == CSSValueWebkitText || CSSParser::isValidSystemColorValue(id) || id == CSSValueMenu) + stop.m_color = CSSValuePool::singleton().createIdentifierValue(id); else - stop.m_color = p->parseColor(stopArg); + stop.m_color = parser.parseColor(stopArg); if (!stop.m_color) return false; } @@ -7288,21 +8719,21 @@ static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CS return true; } -bool CSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient) +bool CSSParser::parseDeprecatedGradient(CSSParserValueList& valueList, RefPtr<CSSValue>& gradient) { // Walk the arguments. - CSSParserValueList* args = valueList->current()->function->args.get(); + CSSParserValueList* args = valueList.current()->function->args.get(); if (!args || args->size() == 0) return false; // The first argument is the gradient type. It is an identifier. CSSGradientType gradientType; - CSSParserValue* a = args->current(); - if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT) + CSSParserValue* argument = args->current(); + if (!argument || argument->unit != CSSPrimitiveValue::CSS_IDENT) return false; - if (equalIgnoringCase(a, "linear")) + if (equalLettersIgnoringASCIICase(*argument, "linear")) gradientType = CSSDeprecatedLinearGradient; - else if (equalIgnoringCase(a, "radial")) + else if (equalLettersIgnoringASCIICase(*argument, "radial")) gradientType = CSSDeprecatedRadialGradient; else return false; @@ -7321,63 +8752,65 @@ bool CSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr<CS } // Comma. - a = args->next(); - if (!isComma(a)) + argument = args->next(); + if (!isComma(argument)) return false; // Next comes the starting point for the gradient as an x y pair. There is no // comma between the x and the y values. // First X. It can be left, right, number or percent. - a = args->next(); - if (!a) + argument = args->next(); + if (!argument) return false; - RefPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true); + RefPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(*argument, true); if (!point) return false; result->setFirstX(point.release()); // First Y. It can be top, bottom, number or percent. - a = args->next(); - if (!a) + argument = args->next(); + if (!argument) return false; - point = parseDeprecatedGradientPoint(a, false); + point = parseDeprecatedGradientPoint(*argument, false); if (!point) return false; result->setFirstY(point.release()); // Comma after the first point. - a = args->next(); - if (!isComma(a)) + argument = args->next(); + if (!isComma(argument)) return false; // For radial gradients only, we now expect a numeric radius. if (gradientType == CSSDeprecatedRadialGradient) { - a = args->next(); - if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER) + argument = args->next(); + // FIXME: This does not handle calculation values. + if (!argument || argument->unit != CSSPrimitiveValue::CSS_NUMBER) return false; - static_cast<CSSRadialGradientValue*>(result.get())->setFirstRadius(createPrimitiveNumericValue(a)); + ValueWithCalculation argumentWithCalculation(*argument); + downcast<CSSRadialGradientValue>(*result).setFirstRadius(createPrimitiveNumericValue(argumentWithCalculation)); // Comma after the first radius. - a = args->next(); - if (!isComma(a)) + argument = args->next(); + if (!isComma(argument)) return false; } // Next is the ending point for the gradient as an x, y pair. // Second X. It can be left, right, number or percent. - a = args->next(); - if (!a) + argument = args->next(); + if (!argument) return false; - point = parseDeprecatedGradientPoint(a, true); + point = parseDeprecatedGradientPoint(*argument, true); if (!point) return false; result->setSecondX(point.release()); // Second Y. It can be top, bottom, number or percent. - a = args->next(); - if (!a) + argument = args->next(); + if (!argument) return false; - point = parseDeprecatedGradientPoint(a, false); + point = parseDeprecatedGradientPoint(*argument, false); if (!point) return false; result->setSecondY(point.release()); @@ -7385,48 +8818,50 @@ bool CSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr<CS // For radial gradients only, we now expect the second radius. if (gradientType == CSSDeprecatedRadialGradient) { // Comma after the second point. - a = args->next(); - if (!isComma(a)) + argument = args->next(); + if (!isComma(argument)) return false; - a = args->next(); - if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER) + argument = args->next(); + // FIXME: This does not handle calculation values. + if (!argument || argument->unit != CSSPrimitiveValue::CSS_NUMBER) return false; - static_cast<CSSRadialGradientValue*>(result.get())->setSecondRadius(createPrimitiveNumericValue(a)); + ValueWithCalculation argumentWithCalculation(*argument); + downcast<CSSRadialGradientValue>(*result).setSecondRadius(createPrimitiveNumericValue(argumentWithCalculation)); } // We now will accept any number of stops (0 or more). - a = args->next(); - while (a) { + argument = args->next(); + while (argument) { // Look for the comma before the next stop. - if (!isComma(a)) + if (!isComma(argument)) return false; // Now examine the stop itself. - a = args->next(); - if (!a) + argument = args->next(); + if (!argument) return false; // The function name needs to be one of "from", "to", or "color-stop." CSSGradientColorStop stop; - if (!parseDeprecatedGradientColorStop(this, a, stop)) + if (!parseDeprecatedGradientColorStop(*this, *argument, stop)) return false; result->addStop(stop); // Advance - a = args->next(); + argument = args->next(); } gradient = result.release(); return true; } -static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal) +static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue& value, bool& isHorizontal) { - if (a->unit != CSSPrimitiveValue::CSS_IDENT) - return 0; + if (value.unit != CSSPrimitiveValue::CSS_IDENT) + return nullptr; - switch (a->id) { + switch (value.id) { case CSSValueLeft: case CSSValueRight: isHorizontal = true; @@ -7436,37 +8871,38 @@ static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, boo isHorizontal = false; break; default: - return 0; + return nullptr; } - return cssValuePool().createIdentifierValue(a->id); + return CSSValuePool::singleton().createIdentifierValue(value.id); } -static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSParser* p, CSSParserValue* value) +static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSParser& parser, CSSParserValue& value) { - CSSValueID id = value->id; - if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor) - return cssValuePool().createIdentifierValue(id); + CSSValueID id = value.id; + if (id == CSSValueWebkitText || CSSParser::isValidSystemColorValue(id) || id == CSSValueMenu || id == CSSValueCurrentcolor) + return CSSValuePool::singleton().createIdentifierValue(id); - return p->parseColor(value); + return parser.parseColor(&value); } -bool CSSParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating) +bool CSSParser::parseDeprecatedLinearGradient(CSSParserValueList& valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating) { RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient); // Walk the arguments. - CSSParserValueList* args = valueList->current()->function->args.get(); + CSSParserValueList* args = valueList.current()->function->args.get(); if (!args || !args->size()) return false; - CSSParserValue* a = args->current(); - if (!a) + CSSParserValue* argument = args->current(); + if (!argument) return false; + ValueWithCalculation argumentWithCalculation(*argument); bool expectComma = false; // Look for angle. - if (validUnit(a, FAngle, CSSStrictMode)) { - result->setAngle(createPrimitiveNumericValue(a)); + if (validateUnit(argumentWithCalculation, FAngle, CSSStrictMode)) { + result->setAngle(createPrimitiveNumericValue(argumentWithCalculation)); args->next(); expectComma = true; @@ -7476,14 +8912,14 @@ bool CSSParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, Ref RefPtr<CSSPrimitiveValue> location; bool isHorizontal = false; - if ((location = valueFromSideKeyword(a, isHorizontal))) { + if ((location = valueFromSideKeyword(*argument, isHorizontal))) { if (isHorizontal) startX = location; else startY = location; - if ((a = args->next())) { - if ((location = valueFromSideKeyword(a, isHorizontal))) { + if ((argument = args->next())) { + if ((location = valueFromSideKeyword(*argument, isHorizontal))) { if (isHorizontal) { if (startX) return false; @@ -7502,13 +8938,13 @@ bool CSSParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, Ref } if (!startX && !startY) - startY = cssValuePool().createIdentifierValue(CSSValueTop); + startY = CSSValuePool::singleton().createIdentifierValue(CSSValueTop); result->setFirstX(startX.release()); result->setFirstY(startY.release()); } - if (!parseGradientColorStops(args, result.get(), expectComma)) + if (!parseGradientColorStops(*args, *result, expectComma)) return false; if (!result->stopCount()) @@ -7518,62 +8954,59 @@ bool CSSParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, Ref return true; } -bool CSSParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating) +bool CSSParser::parseDeprecatedRadialGradient(CSSParserValueList& valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating) { RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient); // Walk the arguments. - CSSParserValueList* args = valueList->current()->function->args.get(); + CSSParserValueList* args = valueList.current()->function->args.get(); if (!args || !args->size()) return false; - CSSParserValue* a = args->current(); - if (!a) + CSSParserValue* argument = args->current(); + if (!argument) return false; bool expectComma = false; // Optional background-position - RefPtr<CSSValue> centerX; - RefPtr<CSSValue> centerY; + RefPtr<CSSPrimitiveValue> centerX; + RefPtr<CSSPrimitiveValue> centerY; // parse2ValuesFillPosition advances the args next pointer. - parse2ValuesFillPosition(args, centerX, centerY); - a = args->current(); - if (!a) + parse2ValuesFillPosition(*args, centerX, centerY); + argument = args->current(); + if (!argument) return false; if (centerX || centerY) { // Comma - if (!isComma(a)) + if (!isComma(argument)) return false; - a = args->next(); - if (!a) + argument = args->next(); + if (!argument) return false; } - ASSERT(!centerX || centerX->isPrimitiveValue()); - ASSERT(!centerY || centerY->isPrimitiveValue()); - - result->setFirstX(static_cast<CSSPrimitiveValue*>(centerX.get())); - result->setSecondX(static_cast<CSSPrimitiveValue*>(centerX.get())); + result->setFirstX(centerX); + result->setSecondX(centerX); // CSS3 radial gradients always share the same start and end point. - result->setFirstY(static_cast<CSSPrimitiveValue*>(centerY.get())); - result->setSecondY(static_cast<CSSPrimitiveValue*>(centerY.get())); + result->setFirstY(centerY); + result->setSecondY(centerY); RefPtr<CSSPrimitiveValue> shapeValue; RefPtr<CSSPrimitiveValue> sizeValue; // Optional shape and/or size in any order. for (int i = 0; i < 2; ++i) { - if (a->unit != CSSPrimitiveValue::CSS_IDENT) + if (argument->unit != CSSPrimitiveValue::CSS_IDENT) break; bool foundValue = false; - switch (a->id) { + switch (argument->id) { case CSSValueCircle: case CSSValueEllipse: - shapeValue = cssValuePool().createIdentifierValue(a->id); + shapeValue = CSSValuePool::singleton().createIdentifierValue(argument->id); foundValue = true; break; case CSSValueClosestSide: @@ -7582,7 +9015,7 @@ bool CSSParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, Ref case CSSValueFarthestCorner: case CSSValueContain: case CSSValueCover: - sizeValue = cssValuePool().createIdentifierValue(a->id); + sizeValue = CSSValuePool::singleton().createIdentifierValue(argument->id); foundValue = true; break; default: @@ -7590,8 +9023,8 @@ bool CSSParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, Ref } if (foundValue) { - a = args->next(); - if (!a) + argument = args->next(); + if (!argument) return false; expectComma = true; @@ -7606,20 +9039,22 @@ bool CSSParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, Ref RefPtr<CSSPrimitiveValue> verticalSize; if (!shapeValue && !sizeValue) { - if (validUnit(a, FLength | FPercent)) { - horizontalSize = createPrimitiveNumericValue(a); - a = args->next(); - if (!a) + ValueWithCalculation hSizeWithCalculation(*argument); + if (validateUnit(hSizeWithCalculation, FLength | FPercent)) { + horizontalSize = createPrimitiveNumericValue(hSizeWithCalculation); + argument = args->next(); + if (!argument) return false; expectComma = true; } - if (validUnit(a, FLength | FPercent)) { - verticalSize = createPrimitiveNumericValue(a); + ValueWithCalculation vSizeWithCalculation(*argument); + if (validateUnit(vSizeWithCalculation, FLength | FPercent)) { + verticalSize = createPrimitiveNumericValue(vSizeWithCalculation); - a = args->next(); - if (!a) + argument = args->next(); + if (!argument) return false; expectComma = true; } @@ -7632,43 +9067,44 @@ bool CSSParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, Ref result->setEndHorizontalSize(horizontalSize); result->setEndVerticalSize(verticalSize); - if (!parseGradientColorStops(args, result.get(), expectComma)) + if (!parseGradientColorStops(*args, *result, expectComma)) return false; gradient = result.release(); return true; } -bool CSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating) +bool CSSParser::parseLinearGradient(CSSParserValueList& valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating) { RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient); - CSSParserValueList* args = valueList->current()->function->args.get(); + CSSParserValueList* args = valueList.current()->function->args.get(); if (!args || !args->size()) return false; - CSSParserValue* a = args->current(); - if (!a) + if (!args->current()) return false; + ValueWithCalculation firstArgumentWithCalculation(*args->current()); + bool expectComma = false; // Look for angle. - if (validUnit(a, FAngle, CSSStrictMode)) { - result->setAngle(createPrimitiveNumericValue(a)); + if (validateUnit(firstArgumentWithCalculation, FAngle, CSSStrictMode)) { + result->setAngle(createPrimitiveNumericValue(firstArgumentWithCalculation)); args->next(); expectComma = true; - } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) { + } else if (firstArgumentWithCalculation.value().unit == CSSPrimitiveValue::CSS_IDENT && equalLettersIgnoringASCIICase(firstArgumentWithCalculation, "to")) { // to [ [left | right] || [top | bottom] ] - a = args->next(); - if (!a) + CSSParserValue* nextArgument = args->next(); + if (!nextArgument) return false; RefPtr<CSSPrimitiveValue> endX, endY; RefPtr<CSSPrimitiveValue> location; bool isHorizontal = false; - location = valueFromSideKeyword(a, isHorizontal); + location = valueFromSideKeyword(*nextArgument, isHorizontal); if (!location) return false; @@ -7677,11 +9113,11 @@ bool CSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSVal else endY = location; - a = args->next(); - if (!a) + nextArgument = args->next(); + if (!nextArgument) return false; - location = valueFromSideKeyword(a, isHorizontal); + location = valueFromSideKeyword(*nextArgument, isHorizontal); if (location) { if (isHorizontal) { if (endX) @@ -7701,7 +9137,7 @@ bool CSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSVal result->setFirstY(endY.release()); } - if (!parseGradientColorStops(args, result.get(), expectComma)) + if (!parseGradientColorStops(*args, *result, expectComma)) return false; if (!result->stopCount()) @@ -7711,16 +9147,16 @@ bool CSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSVal return true; } -bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating) +bool CSSParser::parseRadialGradient(CSSParserValueList& valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating) { RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient); - CSSParserValueList* args = valueList->current()->function->args.get(); + CSSParserValueList* args = valueList.current()->function->args.get(); if (!args || !args->size()) return false; - CSSParserValue* a = args->current(); - if (!a) + CSSParserValue* argument = args->current(); + if (!argument) return false; bool expectComma = false; @@ -7735,14 +9171,15 @@ bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSVal // [ ellipse || [ <length> | <percentage> ]{2} ] | // [ [ circle | ellipse] || <size-keyword> ] for (int i = 0; i < 3; ++i) { - if (a->unit == CSSPrimitiveValue::CSS_IDENT) { + ValueWithCalculation argumentWithCalculation(*argument); + if (argument->unit == CSSPrimitiveValue::CSS_IDENT) { bool badIdent = false; - switch (a->id) { + switch (argument->id) { case CSSValueCircle: case CSSValueEllipse: if (shapeValue) return false; - shapeValue = cssValuePool().createIdentifierValue(a->id); + shapeValue = CSSValuePool::singleton().createIdentifierValue(argument->id); break; case CSSValueClosestSide: case CSSValueClosestCorner: @@ -7750,7 +9187,7 @@ bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSVal case CSSValueFarthestCorner: if (sizeValue || horizontalSize) return false; - sizeValue = cssValuePool().createIdentifierValue(a->id); + sizeValue = CSSValuePool::singleton().createIdentifierValue(argument->id); break; default: badIdent = true; @@ -7759,24 +9196,25 @@ bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSVal if (badIdent) break; - a = args->next(); - if (!a) + argument = args->next(); + if (!argument) return false; - } else if (validUnit(a, FLength | FPercent)) { + } else if (validateUnit(argumentWithCalculation, FLength | FPercent)) { if (sizeValue || horizontalSize) return false; - horizontalSize = createPrimitiveNumericValue(a); + horizontalSize = createPrimitiveNumericValue(argumentWithCalculation); - a = args->next(); - if (!a) + argument = args->next(); + if (!argument) return false; - if (validUnit(a, FLength | FPercent)) { - verticalSize = createPrimitiveNumericValue(a); + ValueWithCalculation vSizeWithCalculation(*argument); + if (validateUnit(vSizeWithCalculation, FLength | FPercent)) { + verticalSize = createPrimitiveNumericValue(vSizeWithCalculation); ++i; - a = args->next(); - if (!a) + argument = args->next(); + if (!argument) return false; } } else @@ -7803,179 +9241,241 @@ bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSVal // Second part of grammar, the center-position clause: // at <position> - RefPtr<CSSValue> centerX; - RefPtr<CSSValue> centerY; - if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) { - a = args->next(); - if (!a) + RefPtr<CSSPrimitiveValue> centerX; + RefPtr<CSSPrimitiveValue> centerY; + if (argument->unit == CSSPrimitiveValue::CSS_IDENT && equalLettersIgnoringASCIICase(*argument, "at")) { + argument = args->next(); + if (!argument) return false; - parseFillPosition(args, centerX, centerY); - ASSERT(centerX->isPrimitiveValue()); - ASSERT(centerY->isPrimitiveValue()); + parseFillPosition(*args, centerX, centerY); if (!(centerX && centerY)) return false; - a = args->current(); - if (!a) + argument = args->current(); + if (!argument) return false; - result->setFirstX(static_cast<CSSPrimitiveValue*>(centerX.get())); - result->setFirstY(static_cast<CSSPrimitiveValue*>(centerY.get())); + + result->setFirstX(centerX); + result->setFirstY(centerY); // Right now, CSS radial gradients have the same start and end centers. - result->setSecondX(static_cast<CSSPrimitiveValue*>(centerX.get())); - result->setSecondY(static_cast<CSSPrimitiveValue*>(centerY.get())); + result->setSecondX(centerX); + result->setSecondY(centerY); } if (shapeValue || sizeValue || horizontalSize || centerX || centerY) expectComma = true; - if (!parseGradientColorStops(args, result.get(), expectComma)) + if (!parseGradientColorStops(*args, *result, expectComma)) return false; gradient = result.release(); return true; } -bool CSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma) +bool CSSParser::parseGradientColorStops(CSSParserValueList& valueList, CSSGradientValue& gradient, bool expectComma) { - CSSParserValue* a = valueList->current(); + CSSParserValue* value = valueList.current(); + bool previousStopWasMidpoint = true; // Now look for color stops. - while (a) { + while (value) { // Look for the comma before the next stop. if (expectComma) { - if (!isComma(a)) + if (!isComma(value)) return false; - a = valueList->next(); - if (!a) + value = valueList.next(); + if (!value) return false; } // <color-stop> = <color> [ <percentage> | <length> ]? CSSGradientColorStop stop; - stop.m_color = parseGradientColorOrKeyword(this, a); - if (!stop.m_color) - return false; + stop.m_color = parseGradientColorOrKeyword(*this, *value); + if (!stop.m_color) { + if (previousStopWasMidpoint) // 2 midpoints in a row is not allowed. This also catches starting with a midpoint. + return false; - a = valueList->next(); - if (a) { - if (validUnit(a, FLength | FPercent)) { - stop.m_position = createPrimitiveNumericValue(a); - a = valueList->next(); - } + stop.isMidpoint = true; + } else + value = valueList.next(); + + previousStopWasMidpoint = stop.isMidpoint; + + if (value) { + ValueWithCalculation valueWithCalculation(*value); + if (validateUnit(valueWithCalculation, FLength | FPercent)) { + stop.m_position = createPrimitiveNumericValue(valueWithCalculation); + value = valueList.next(); + } else if (stop.isMidpoint) + return false; } - gradient->addStop(stop); + gradient.addStop(stop); expectComma = true; } + // We can't end on a midpoint. + if (previousStopWasMidpoint) + return false; + // Must have 2 or more stops to be valid. - return gradient->stopCount() >= 2; + return gradient.stopCount() >= 2; } -bool CSSParser::isGeneratedImageValue(CSSParserValue* val) const +bool CSSParser::isGeneratedImageValue(CSSParserValue& value) const { - if (val->unit != CSSParserValue::Function) + if (value.unit != CSSParserValue::Function) return false; - return equalIgnoringCase(val->function->name, "-webkit-gradient(") - || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(") - || equalIgnoringCase(val->function->name, "linear-gradient(") - || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(") - || equalIgnoringCase(val->function->name, "repeating-linear-gradient(") - || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(") - || equalIgnoringCase(val->function->name, "radial-gradient(") - || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(") - || equalIgnoringCase(val->function->name, "repeating-radial-gradient(") - || equalIgnoringCase(val->function->name, "-webkit-canvas(") - || equalIgnoringCase(val->function->name, "-webkit-cross-fade("); + return equalLettersIgnoringASCIICase(value.function->name, "-webkit-gradient(") + || equalLettersIgnoringASCIICase(value.function->name, "-webkit-linear-gradient(") + || equalLettersIgnoringASCIICase(value.function->name, "linear-gradient(") + || equalLettersIgnoringASCIICase(value.function->name, "-webkit-repeating-linear-gradient(") + || equalLettersIgnoringASCIICase(value.function->name, "repeating-linear-gradient(") + || equalLettersIgnoringASCIICase(value.function->name, "-webkit-radial-gradient(") + || equalLettersIgnoringASCIICase(value.function->name, "radial-gradient(") + || equalLettersIgnoringASCIICase(value.function->name, "-webkit-repeating-radial-gradient(") + || equalLettersIgnoringASCIICase(value.function->name, "repeating-radial-gradient(") + || equalLettersIgnoringASCIICase(value.function->name, "-webkit-canvas(") + || equalLettersIgnoringASCIICase(value.function->name, "-webkit-cross-fade(") + || equalLettersIgnoringASCIICase(value.function->name, "filter(") + || equalLettersIgnoringASCIICase(value.function->name, "-webkit-filter(") + || equalLettersIgnoringASCIICase(value.function->name, "-webkit-named-image("); } -bool CSSParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value) +bool CSSParser::parseGeneratedImage(CSSParserValueList& valueList, RefPtr<CSSValue>& value) { - CSSParserValue* val = valueList->current(); + CSSParserValue& parserValue = *valueList.current(); - if (val->unit != CSSParserValue::Function) + if (parserValue.unit != CSSParserValue::Function) return false; - if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) + if (equalLettersIgnoringASCIICase(parserValue.function->name, "-webkit-gradient(")) return parseDeprecatedGradient(valueList, value); - if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")) + if (equalLettersIgnoringASCIICase(parserValue.function->name, "-webkit-linear-gradient(")) return parseDeprecatedLinearGradient(valueList, value, NonRepeating); - if (equalIgnoringCase(val->function->name, "linear-gradient(")) + if (equalLettersIgnoringASCIICase(parserValue.function->name, "linear-gradient(")) return parseLinearGradient(valueList, value, NonRepeating); - if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")) + if (equalLettersIgnoringASCIICase(parserValue.function->name, "-webkit-repeating-linear-gradient(")) return parseDeprecatedLinearGradient(valueList, value, Repeating); - if (equalIgnoringCase(val->function->name, "repeating-linear-gradient(")) + if (equalLettersIgnoringASCIICase(parserValue.function->name, "repeating-linear-gradient(")) return parseLinearGradient(valueList, value, Repeating); - if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")) + if (equalLettersIgnoringASCIICase(parserValue.function->name, "-webkit-radial-gradient(")) return parseDeprecatedRadialGradient(valueList, value, NonRepeating); - if (equalIgnoringCase(val->function->name, "radial-gradient(")) + if (equalLettersIgnoringASCIICase(parserValue.function->name, "radial-gradient(")) return parseRadialGradient(valueList, value, NonRepeating); - if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")) + if (equalLettersIgnoringASCIICase(parserValue.function->name, "-webkit-repeating-radial-gradient(")) return parseDeprecatedRadialGradient(valueList, value, Repeating); - if (equalIgnoringCase(val->function->name, "repeating-radial-gradient(")) + if (equalLettersIgnoringASCIICase(parserValue.function->name, "repeating-radial-gradient(")) return parseRadialGradient(valueList, value, Repeating); - if (equalIgnoringCase(val->function->name, "-webkit-canvas(")) + if (equalLettersIgnoringASCIICase(parserValue.function->name, "-webkit-canvas(")) return parseCanvas(valueList, value); - if (equalIgnoringCase(val->function->name, "-webkit-cross-fade(")) + if (equalLettersIgnoringASCIICase(parserValue.function->name, "-webkit-cross-fade(")) return parseCrossfade(valueList, value); + if (equalLettersIgnoringASCIICase(parserValue.function->name, "filter(") || equalLettersIgnoringASCIICase(parserValue.function->name, "-webkit-filter(")) + return parseFilterImage(valueList, value); + + if (equalLettersIgnoringASCIICase(parserValue.function->name, "-webkit-named-image(")) + return parseNamedImage(valueList, value); + return false; } -bool CSSParser::parseCrossfade(CSSParserValueList* valueList, RefPtr<CSSValue>& crossfade) +bool CSSParser::parseFilterImage(CSSParserValueList& valueList, RefPtr<CSSValue>& filter) +{ + RefPtr<CSSFilterImageValue> result; + + // Walk the arguments. + CSSParserValueList* args = valueList.current()->function->args.get(); + if (!args) + return false; + CSSParserValue* value = args->current(); + RefPtr<CSSValue> imageValue; + RefPtr<CSSValue> filterValue; + + if (!value) + return false; + + // The first argument is the image. It is a fill image. + if (!parseFillImage(*args, imageValue)) { + if (value->unit == CSSPrimitiveValue::CSS_STRING) + imageValue = CSSImageValue::create(completeURL(value->string)); + else + return false; + } + + value = args->next(); + + // Skip a comma + if (!isComma(value)) + return false; + value = args->next(); + + if (!value || !parseFilter(*args, filterValue)) + return false; + value = args->next(); + + result = CSSFilterImageValue::create(imageValue.releaseNonNull(), filterValue.releaseNonNull()); + + filter = result; + + return true; +} + +bool CSSParser::parseCrossfade(CSSParserValueList& valueList, RefPtr<CSSValue>& crossfade) { RefPtr<CSSCrossfadeValue> result; // Walk the arguments. - CSSParserValueList* args = valueList->current()->function->args.get(); + CSSParserValueList* args = valueList.current()->function->args.get(); if (!args || args->size() != 5) return false; - CSSParserValue* a = args->current(); + CSSParserValue* argument = args->current(); RefPtr<CSSValue> fromImageValue; RefPtr<CSSValue> toImageValue; // The first argument is the "from" image. It is a fill image. - if (!a || !parseFillImage(args, fromImageValue)) + if (!argument || !parseFillImage(*args, fromImageValue)) return false; - a = args->next(); + argument = args->next(); // Skip a comma - if (!isComma(a)) + if (!isComma(argument)) return false; - a = args->next(); + argument = args->next(); // The second argument is the "to" image. It is a fill image. - if (!a || !parseFillImage(args, toImageValue)) + if (!argument || !parseFillImage(*args, toImageValue)) return false; - a = args->next(); + argument = args->next(); // Skip a comma - if (!isComma(a)) + if (!isComma(argument)) return false; - a = args->next(); + argument = args->next(); // The third argument is the crossfade value. It is a percentage or a fractional number. RefPtr<CSSPrimitiveValue> percentage; - if (!a) + if (!argument) return false; - if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE) - percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER); - else if (a->unit == CSSPrimitiveValue::CSS_NUMBER) - percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER); + if (argument->unit == CSSPrimitiveValue::CSS_PERCENTAGE) + percentage = CSSValuePool::singleton().createValue(clampTo<double>(argument->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER); + else if (argument->unit == CSSPrimitiveValue::CSS_NUMBER) + percentage = CSSValuePool::singleton().createValue(clampTo<double>(argument->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER); else return false; @@ -7987,10 +9487,10 @@ bool CSSParser::parseCrossfade(CSSParserValueList* valueList, RefPtr<CSSValue>& return true; } -bool CSSParser::parseCanvas(CSSParserValueList* valueList, RefPtr<CSSValue>& canvas) +bool CSSParser::parseCanvas(CSSParserValueList& valueList, RefPtr<CSSValue>& canvas) { // Walk the arguments. - CSSParserValueList* args = valueList->current()->function->args.get(); + CSSParserValueList* args = valueList.current()->function->args.get(); if (!args || args->size() != 1) return false; @@ -8003,8 +9503,23 @@ bool CSSParser::parseCanvas(CSSParserValueList* valueList, RefPtr<CSSValue>& can return true; } +bool CSSParser::parseNamedImage(CSSParserValueList& valueList, RefPtr<CSSValue>& namedImage) +{ + CSSParserValueList* args = valueList.current()->function->args.get(); + if (!args || args->size() != 1) + return false; + + // The only argument is the image name. + CSSParserValue* value = args->current(); + if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT) + return false; + + namedImage = CSSNamedImageValue::create(value->string); + return true; +} + #if ENABLE(CSS_IMAGE_RESOLUTION) -PassRefPtr<CSSValue> CSSParser::parseImageResolution() +RefPtr<CSSValue> CSSParser::parseImageResolution() { RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); bool haveResolution = false; @@ -8013,53 +9528,54 @@ PassRefPtr<CSSValue> CSSParser::parseImageResolution() CSSParserValue* value = m_valueList->current(); while (value) { + ValueWithCalculation valueWithCalculation(*value); if (!haveFromImage && value->id == CSSValueFromImage) { - list->append(cssValuePool().createIdentifierValue(value->id)); + list->append(CSSValuePool::singleton().createIdentifierValue(value->id)); haveFromImage = true; } else if (!haveSnap && value->id == CSSValueSnap) { - list->append(cssValuePool().createIdentifierValue(value->id)); + list->append(CSSValuePool::singleton().createIdentifierValue(value->id)); haveSnap = true; - } else if (!haveResolution && validUnit(value, FResolution | FNonNeg) && value->fValue > 0) { - list->append(createPrimitiveNumericValue(value)); + } else if (!haveResolution && validateUnit(valueWithCalculation, FResolution | FNonNeg) && value->fValue > 0) { + list->append(createPrimitiveNumericValue(valueWithCalculation)); haveResolution = true; } else - return 0; + return nullptr; value = m_valueList->next(); } if (!list->length()) - return 0; + return nullptr; if (!haveFromImage && !haveResolution) - return 0; - return list.release(); + return nullptr; + return list; } #endif #if ENABLE(CSS_IMAGE_SET) -PassRefPtr<CSSValue> CSSParser::parseImageSet() +RefPtr<CSSValue> CSSParser::parseImageSet() { - CSSParserValue* value = m_valueList->current(); - ASSERT(value->unit == CSSParserValue::Function); + CSSParserValue& value = *m_valueList->current(); + ASSERT(value.unit == CSSParserValue::Function); - CSSParserValueList* functionArgs = value->function->args.get(); + CSSParserValueList* functionArgs = value.function->args.get(); if (!functionArgs || !functionArgs->size() || !functionArgs->current()) - return 0; + return nullptr; RefPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create(); CSSParserValue* arg = functionArgs->current(); while (arg) { if (arg->unit != CSSPrimitiveValue::CSS_URI) - return 0; + return nullptr; imageSet->append(CSSImageValue::create(completeURL(arg->string))); arg = functionArgs->next(); if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION) - return 0; + return nullptr; double imageScaleFactor = 0; const String& string = arg->string; unsigned length = string.length(); if (!length) - return 0; + return nullptr; if (string.is8Bit()) { const LChar* start = string.characters8(); parseDouble(start, start + length, 'x', imageScaleFactor); @@ -8068,8 +9584,8 @@ PassRefPtr<CSSValue> CSSParser::parseImageSet() parseDouble(start, start + length, 'x', imageScaleFactor); } if (imageScaleFactor <= 0) - return 0; - imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER)); + return nullptr; + imageSet->append(CSSValuePool::singleton().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER)); // If there are no more arguments, we're done. arg = functionArgs->next(); @@ -8078,13 +9594,13 @@ PassRefPtr<CSSValue> CSSParser::parseImageSet() // If there are more arguments, they should be after a comma. if (!isComma(arg)) - return 0; + return nullptr; // Skip the comma and move on to the next argument. arg = functionArgs->next(); } - return imageSet.release(); + return imageSet; } #endif @@ -8347,40 +9863,40 @@ private: CSSParser::Units m_unit; }; -PassRefPtr<CSSValueList> CSSParser::parseTransform() +RefPtr<CSSValueList> CSSParser::parseTransform() { if (!m_valueList) - return 0; + return nullptr; RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { - RefPtr<CSSValue> parsedTransformValue = parseTransformValue(value); + RefPtr<CSSValue> parsedTransformValue = parseTransformValue(*value); if (!parsedTransformValue) - return 0; + return nullptr; - list->append(parsedTransformValue.release()); + list->append(parsedTransformValue.releaseNonNull()); } - return list.release(); + return list; } -PassRefPtr<CSSValue> CSSParser::parseTransformValue(CSSParserValue *value) +RefPtr<CSSValue> CSSParser::parseTransformValue(CSSParserValue& value) { - if (value->unit != CSSParserValue::Function || !value->function) - return 0; + if (value.unit != CSSParserValue::Function || !value.function) + return nullptr; // Every primitive requires at least one argument. - CSSParserValueList* args = value->function->args.get(); + CSSParserValueList* args = value.function->args.get(); if (!args) - return 0; + return nullptr; // See if the specified primitive is one we understand. - TransformOperationInfo info(value->function->name); + TransformOperationInfo info(value.function->name); if (info.unknown()) - return 0; + return nullptr; if (!info.hasCorrectArgCount(args->size())) - return 0; + return nullptr; // The transform is a list of functional primitives that specify transform operations. // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation. @@ -8389,41 +9905,42 @@ PassRefPtr<CSSValue> CSSParser::parseTransformValue(CSSParserValue *value) RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(info.type()); // Snag our values. - CSSParserValue* a = args->current(); + CSSParserValue* argument = args->current(); unsigned argNumber = 0; - while (a) { + while (argument) { + ValueWithCalculation argumentWithCalculation(*argument); CSSParser::Units unit = info.unit(); if (info.type() == WebKitCSSTransformValue::Rotate3DTransformOperation && argNumber == 3) { // 4th param of rotate3d() is an angle rather than a bare number, validate it as such - if (!validUnit(a, FAngle, CSSStrictMode)) - return 0; + if (!validateUnit(argumentWithCalculation, FAngle, CSSStrictMode)) + return nullptr; } else if (info.type() == WebKitCSSTransformValue::Translate3DTransformOperation && argNumber == 2) { // 3rd param of translate3d() cannot be a percentage - if (!validUnit(a, FLength, CSSStrictMode)) - return 0; + if (!validateUnit(argumentWithCalculation, FLength, CSSStrictMode)) + return nullptr; } else if (info.type() == WebKitCSSTransformValue::TranslateZTransformOperation && !argNumber) { // 1st param of translateZ() cannot be a percentage - if (!validUnit(a, FLength, CSSStrictMode)) - return 0; + if (!validateUnit(argumentWithCalculation, FLength, CSSStrictMode)) + return nullptr; } else if (info.type() == WebKitCSSTransformValue::PerspectiveTransformOperation && !argNumber) { // 1st param of perspective() must be a non-negative number (deprecated) or length. - if (!validUnit(a, FNumber | FLength | FNonNeg, CSSStrictMode)) - return 0; - } else if (!validUnit(a, unit, CSSStrictMode)) - return 0; + if (!validateUnit(argumentWithCalculation, FNumber | FLength | FNonNeg, CSSStrictMode)) + return nullptr; + } else if (!validateUnit(argumentWithCalculation, unit, CSSStrictMode)) + return nullptr; // Add the value to the current transform operation. - transformValue->append(createPrimitiveNumericValue(a)); + transformValue->append(createPrimitiveNumericValue(argumentWithCalculation)); - a = args->next(); - if (!a) + argument = args->next(); + if (!argument) break; - if (a->unit != CSSParserValue::Operator || a->iValue != ',') - return 0; - a = args->next(); + if (argument->unit != CSSParserValue::Operator || argument->iValue != ',') + return nullptr; + argument = args->next(); - argNumber++; + ++argNumber; } return transformValue.release(); @@ -8442,626 +9959,35 @@ bool CSSParser::isCompositeOperator(CSSValueID valueID) return valueID >= CSSValueClear && valueID <= CSSValueXor; } -#if ENABLE(CSS_FILTERS) - static void filterInfoForName(const CSSParserString& name, WebKitCSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount) { - if (equalIgnoringCase(name, "grayscale(")) + if (equalLettersIgnoringASCIICase(name, "grayscale(")) filterType = WebKitCSSFilterValue::GrayscaleFilterOperation; - else if (equalIgnoringCase(name, "sepia(")) + else if (equalLettersIgnoringASCIICase(name, "sepia(")) filterType = WebKitCSSFilterValue::SepiaFilterOperation; - else if (equalIgnoringCase(name, "saturate(")) + else if (equalLettersIgnoringASCIICase(name, "saturate(")) filterType = WebKitCSSFilterValue::SaturateFilterOperation; - else if (equalIgnoringCase(name, "hue-rotate(")) + else if (equalLettersIgnoringASCIICase(name, "hue-rotate(")) filterType = WebKitCSSFilterValue::HueRotateFilterOperation; - else if (equalIgnoringCase(name, "invert(")) + else if (equalLettersIgnoringASCIICase(name, "invert(")) filterType = WebKitCSSFilterValue::InvertFilterOperation; - else if (equalIgnoringCase(name, "opacity(")) + else if (equalLettersIgnoringASCIICase(name, "opacity(")) filterType = WebKitCSSFilterValue::OpacityFilterOperation; - else if (equalIgnoringCase(name, "brightness(")) + else if (equalLettersIgnoringASCIICase(name, "brightness(")) filterType = WebKitCSSFilterValue::BrightnessFilterOperation; - else if (equalIgnoringCase(name, "contrast(")) + else if (equalLettersIgnoringASCIICase(name, "contrast(")) filterType = WebKitCSSFilterValue::ContrastFilterOperation; - else if (equalIgnoringCase(name, "blur(")) + else if (equalLettersIgnoringASCIICase(name, "blur(")) filterType = WebKitCSSFilterValue::BlurFilterOperation; - else if (equalIgnoringCase(name, "drop-shadow(")) { + else if (equalLettersIgnoringASCIICase(name, "drop-shadow(")) { filterType = WebKitCSSFilterValue::DropShadowFilterOperation; maximumArgumentCount = 4; // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed. } -#if ENABLE(CSS_SHADERS) - else if (equalIgnoringCase(name, "custom(")) - filterType = WebKitCSSFilterValue::CustomFilterOperation; -#endif -} - -#if ENABLE(CSS_SHADERS) -static bool acceptCommaOperator(CSSParserValueList* argsList) -{ - if (CSSParserValue* arg = argsList->current()) { - if (!isComma(arg)) - return false; - argsList->next(); - } - return true; -} - -PassRefPtr<WebKitCSSArrayFunctionValue> CSSParser::parseCustomFilterArrayFunction(CSSParserValue* value) -{ - ASSERT(value->unit == CSSParserValue::Function && value->function); - - if (!equalIgnoringCase(value->function->name, "array(")) - return 0; - - CSSParserValueList* arrayArgsParserValueList = value->function->args.get(); - if (!arrayArgsParserValueList || !arrayArgsParserValueList->size()) - return 0; - - // array() values are comma separated. - RefPtr<WebKitCSSArrayFunctionValue> arrayFunction = WebKitCSSArrayFunctionValue::create(); - while (true) { - // We parse pairs <Value, Comma> at each step. - CSSParserValue* currentParserValue = arrayArgsParserValueList->current(); - if (!currentParserValue || !validUnit(currentParserValue, FNumber, CSSStrictMode)) - return 0; - - RefPtr<CSSValue> arrayValue = cssValuePool().createValue(currentParserValue->fValue, CSSPrimitiveValue::CSS_NUMBER); - arrayFunction->append(arrayValue.release()); - - CSSParserValue* nextParserValue = arrayArgsParserValueList->next(); - if (!nextParserValue) - break; - - if (!isComma(nextParserValue)) - return 0; - - arrayArgsParserValueList->next(); - } - - return arrayFunction; -} - -PassRefPtr<WebKitCSSMatFunctionValue> CSSParser::parseMatValue(CSSParserValue* value) -{ - if (value->unit != CSSParserValue::Function || !value->function) - return 0; - - unsigned numberOfValues = 0; - if (equalIgnoringCase(value->function->name, "mat2(")) - numberOfValues = 4; - else if (equalIgnoringCase(value->function->name, "mat3(")) - numberOfValues = 9; - else if (equalIgnoringCase(value->function->name, "mat4(")) - numberOfValues = 16; - else - return 0; - - CSSParserValueList* args = value->function->args.get(); - if (!args || args->size() != (numberOfValues * 2 - 1)) - return 0; - - RefPtr<WebKitCSSMatFunctionValue> matValueList = WebKitCSSMatFunctionValue::create(); - CSSParserValue* arg = args->current(); - while (arg) { - if (!validUnit(arg, FNumber, CSSStrictMode)) - return 0; - matValueList->append(cssValuePool().createValue(arg->fValue, CSSPrimitiveValue::CSS_NUMBER)); - arg = args->next(); - - if (!arg) - break; - - if (!isComma(arg)) - return 0; - - arg = args->next(); - } - - if (!matValueList || matValueList->length() != numberOfValues) - return 0; - - return matValueList.release(); -} - -PassRefPtr<WebKitCSSMixFunctionValue> CSSParser::parseMixFunction(CSSParserValue* value) -{ - ASSERT(value->unit == CSSParserValue::Function && value->function); - - if (!equalIgnoringCase(value->function->name, "mix(")) - return 0; - - CSSParserValueList* argsList = value->function->args.get(); - if (!argsList) - return 0; - - unsigned numArgs = argsList->size(); - if (numArgs < 1 || numArgs > 3) - return 0; - - RefPtr<WebKitCSSMixFunctionValue> mixFunction = WebKitCSSMixFunctionValue::create(); - - bool hasBlendMode = false; - bool hasAlphaCompositing = false; - CSSParserValue* arg; - while ((arg = argsList->current())) { - RefPtr<CSSValue> value; - - unsigned argNumber = argsList->currentIndex(); - if (!argNumber) { - if (arg->unit == CSSPrimitiveValue::CSS_URI) { - KURL shaderURL = completeURL(arg->string); - value = WebKitCSSShaderValue::create(shaderURL.string()); - } - } else if (argNumber == 1 || argNumber == 2) { - if (!hasBlendMode && isBlendMode(arg->id)) { - hasBlendMode = true; - value = cssValuePool().createIdentifierValue(arg->id); - } else if (!hasAlphaCompositing && isCompositeOperator(arg->id)) { - hasAlphaCompositing = true; - value = cssValuePool().createIdentifierValue(arg->id); - } - } - - if (!value) - return 0; - - mixFunction->append(value.release()); - - arg = argsList->next(); - } - - return mixFunction; -} - -PassRefPtr<CSSValueList> CSSParser::parseCustomFilterParameters(CSSParserValueList* argsList) -{ - // - // params: [<param-def>[,<param-def>*]] - // param-def: <param-name>wsp<param-value> - // param-name: <ident> - // param-value: true|false[wsp+true|false]{0-3} | - // <number>[wsp+<number>]{0-3} | - // <array> | - // <transform> | - // <texture(<uri>)> - // array: 'array('<number>[wsp<number>]*')' - // css-3d-transform: <transform-function>;[<transform-function>]* - // transform: <css-3d-transform> | <mat> - // mat: 'mat2('<number>(,<number>){3}')' | - // 'mat3('<number>(,<number>){8}')' | - // 'mat4('<number>(,<number>){15}')' ) - // - - RefPtr<CSSValueList> paramList = CSSValueList::createCommaSeparated(); - - while (CSSParserValue* arg = argsList->current()) { - if (arg->unit != CSSPrimitiveValue::CSS_IDENT) - return 0; - - RefPtr<CSSValueList> parameter = CSSValueList::createSpaceSeparated(); - parameter->append(createPrimitiveStringValue(arg)); - - arg = argsList->next(); - if (!arg) - return 0; - - RefPtr<CSSValue> parameterValue; - - if (arg->unit == CSSParserValue::Function && arg->function) { - // FIXME: Implement parsing for the other parameter types. - // textures: https://bugs.webkit.org/show_bug.cgi?id=71442 - if (equalIgnoringCase(arg->function->name, "array(")) { - parameterValue = parseCustomFilterArrayFunction(arg); - // This parsing step only consumes function arguments, - // argsList is therefore moved forward explicitely. - argsList->next(); - } else { - // Parse mat2, mat3 and mat4 functions. - parameterValue = parseMatValue(arg); - if (!parameterValue && arg) - parameterValue = parseCustomFilterTransform(argsList); - else if (parameterValue) - argsList->next(); - } - } else if (validUnit(arg, FNumber, CSSStrictMode)) { - RefPtr<CSSValueList> paramValueList = CSSValueList::createSpaceSeparated(); - while (arg) { - // If we hit a comma, it means that we finished this parameter's values. - if (isComma(arg)) - break; - if (!validUnit(arg, FNumber, CSSStrictMode)) - return 0; - paramValueList->append(cssValuePool().createValue(arg->fValue, CSSPrimitiveValue::CSS_NUMBER)); - arg = argsList->next(); - } - if (!paramValueList->length() || paramValueList->length() > 4) - return 0; - parameterValue = paramValueList.release(); - } - if (!parameterValue && arg) { - // All parameter values need to be CSSValueLists. - RefPtr<CSSValueList> paramValueList = CSSValueList::createSpaceSeparated(); - RefPtr<CSSPrimitiveValue> colorValue = parseColor(arg); - if (!colorValue) - return 0; - paramValueList->append(colorValue.release()); - parameterValue = paramValueList.release(); - arg = argsList->next(); - } - - if (!parameterValue || !acceptCommaOperator(argsList)) - return 0; - - parameter->append(parameterValue.release()); - paramList->append(parameter.release()); - } - - return paramList; } -PassRefPtr<WebKitCSSFilterValue> CSSParser::parseCustomFilterFunctionWithAtRuleReferenceSyntax(CSSParserValue* value) -{ - // - // Custom filter function "at-rule reference" syntax: - // - // custom(<filter-name>wsp[,wsp<params>]) - // - // filter-name: <filter-name> - // params: See the comment in CSSParser::parseCustomFilterParameters. - // - - ASSERT(value->function); - - CSSParserValueList* argsList = value->function->args.get(); - if (!argsList || !argsList->size()) - return 0; - - // 1. Parse the filter name. - CSSParserValue* arg = argsList->current(); - if (arg->unit != CSSPrimitiveValue::CSS_IDENT) - return 0; - - RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::CustomFilterOperation); - - RefPtr<CSSValue> filterName = createPrimitiveStringValue(arg); - filterValue->append(filterName); - argsList->next(); - - if (!acceptCommaOperator(argsList)) - return 0; - - // 2. Parse the parameters. - RefPtr<CSSValueList> paramList = parseCustomFilterParameters(argsList); - if (!paramList) - return 0; - - if (paramList->length()) - filterValue->append(paramList.release()); - - return filterValue; -} - -// FIXME: The custom filters "inline" syntax is deprecated. We will remove it eventually. -PassRefPtr<WebKitCSSFilterValue> CSSParser::parseCustomFilterFunctionWithInlineSyntax(CSSParserValue* value) -{ - // - // Custom filter function "inline" syntax: - // - // custom(<vertex-shader>[wsp<fragment-shader>][,<vertex-mesh>][,<params>]) - // - // vertexShader: <uri> | none - // fragmentShader: <uri> | none | mix(<uri> [ <blend-mode> || <alpha-compositing> ]?) - // - // blend-mode: normal | multiply | screen | overlay | darken | lighten | color-dodge | - // color-burn | hard-light | soft-light | difference | exclusion | hue | - // saturation | color | luminosity - // alpha-compositing: clear | src | dst | src-over | dst-over | src-in | dst-in | - // src-out | dst-out | src-atop | dst-atop | xor | plus - // - // vertexMesh: +<integer>{1,2}[wsp<box>][wsp'detached'] - // box: filter-box | border-box | padding-box | content-box - // - // params: See the comment in CSSParser::parseCustomFilterParameters. - // - - ASSERT(value->function); - - CSSParserValueList* argsList = value->function->args.get(); - if (!argsList) - return 0; - - RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::CustomFilterOperation); - - // 1. Parse the shader URLs: <vertex-shader>[wsp<fragment-shader>] - RefPtr<CSSValueList> shadersList = CSSValueList::createSpaceSeparated(); - bool hadAtLeastOneCustomShader = false; - CSSParserValue* arg; - while ((arg = argsList->current())) { - RefPtr<CSSValue> value; - if (arg->id == CSSValueNone) - value = cssValuePool().createIdentifierValue(CSSValueNone); - else if (arg->unit == CSSPrimitiveValue::CSS_URI) { - KURL shaderURL = completeURL(arg->string); - value = WebKitCSSShaderValue::create(shaderURL.string()); - hadAtLeastOneCustomShader = true; - } else if (argsList->currentIndex() == 1 && arg->unit == CSSParserValue::Function) { - if (!(value = parseMixFunction(arg))) - return 0; - hadAtLeastOneCustomShader = true; - } - - if (!value) - break; - shadersList->append(value.release()); - argsList->next(); - } - - if (!shadersList->length() || !hadAtLeastOneCustomShader || shadersList->length() > 2 || !acceptCommaOperator(argsList)) - return 0; - - filterValue->append(shadersList.release()); - - // 2. Parse the mesh size <vertex-mesh> - RefPtr<CSSValueList> meshSizeList = CSSValueList::createSpaceSeparated(); - - while ((arg = argsList->current())) { - if (!validUnit(arg, FInteger | FNonNeg, CSSStrictMode)) - break; - int integerValue = clampToInteger(arg->fValue); - // According to the specification we can only accept positive non-zero values. - if (integerValue < 1) - return 0; - meshSizeList->append(cssValuePool().createValue(integerValue, CSSPrimitiveValue::CSS_NUMBER)); - argsList->next(); - } - - if (meshSizeList->length() > 2) - return 0; - - // FIXME: For legacy content, we accept the mesh box types. We don't do anything else with them. - // Eventually, we'll remove them completely. - // https://bugs.webkit.org/show_bug.cgi?id=103778 - if ((arg = argsList->current()) && (arg->id == CSSValueBorderBox || arg->id == CSSValuePaddingBox - || arg->id == CSSValueContentBox || arg->id == CSSValueFilterBox)) - argsList->next(); - - if ((arg = argsList->current()) && arg->id == CSSValueDetached) { - meshSizeList->append(cssValuePool().createIdentifierValue(arg->id)); - argsList->next(); - } - - if (meshSizeList->length()) { - if (!acceptCommaOperator(argsList)) - return 0; - filterValue->append(meshSizeList.release()); - } - - // 3. Parse the parameters. - RefPtr<CSSValueList> paramList = parseCustomFilterParameters(argsList); - if (!paramList) - return 0; - - if (paramList->length()) - filterValue->append(paramList.release()); - - return filterValue; -} - -PassRefPtr<WebKitCSSFilterValue> CSSParser::parseCustomFilterFunction(CSSParserValue* value) -{ - ASSERT(value->function); - - // Look ahead to determine which syntax the custom function is using. - // Both the at-rule reference syntax and the inline syntax require at least one argument. - CSSParserValueList* argsList = value->function->args.get(); - if (!argsList || !argsList->size()) - return 0; - - // The at-rule reference syntax expects a single ident or an ident followed by a comma. - // e.g. custom(my-filter) or custom(my-filter, ...) - // In contrast, when the inline syntax starts with an ident like "none", it expects a uri or a mix function next. - // e.g. custom(none url(...)) or custom(none mix(...) - bool isAtRuleReferenceSyntax = argsList->valueAt(0)->unit == CSSPrimitiveValue::CSS_IDENT - && (argsList->size() == 1 || isComma(argsList->valueAt(1))); - return isAtRuleReferenceSyntax ? parseCustomFilterFunctionWithAtRuleReferenceSyntax(value) : parseCustomFilterFunctionWithInlineSyntax(value); -} - -PassRefPtr<CSSValueList> CSSParser::parseCustomFilterTransform(CSSParserValueList* valueList) -{ - if (!valueList) - return 0; - - // CSS Shaders' custom() transforms are space separated and comma terminated. - RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); - for (CSSParserValue* value = valueList->current(); value; value = valueList->next()) { - if (isComma(value)) - break; - - RefPtr<CSSValue> parsedTransformValue = parseTransformValue(value); - if (!parsedTransformValue) - return 0; - - list->append(parsedTransformValue.release()); - } - - return list.release(); -} - -PassRefPtr<WebKitCSSShaderValue> CSSParser::parseFilterRuleSrcUriAndFormat(CSSParserValueList* valueList) -{ - CSSParserValue* value = valueList->current(); - ASSERT(value && value->unit == CSSPrimitiveValue::CSS_URI); - RefPtr<WebKitCSSShaderValue> shaderValue = WebKitCSSShaderValue::create(completeURL(value->string)); - - value = valueList->next(); - if (value && value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "format(")) { - CSSParserValueList* args = value->function->args.get(); - if (!args || args->size() != 1) - return 0; - - CSSParserValue* arg = args->current(); - if (arg->unit != CSSPrimitiveValue::CSS_STRING) - return 0; - - shaderValue->setFormat(arg->string); - valueList->next(); - } - - return shaderValue.release(); -} - -bool CSSParser::parseFilterRuleSrc() -{ - RefPtr<CSSValueList> srcList = CSSValueList::createCommaSeparated(); - - CSSParserValue* value = m_valueList->current(); - while (value) { - if (value->unit != CSSPrimitiveValue::CSS_URI) - return false; - - RefPtr<WebKitCSSShaderValue> shaderValue = parseFilterRuleSrcUriAndFormat(m_valueList.get()); - if (!shaderValue) - return false; - srcList->append(shaderValue.release()); - - if (!acceptCommaOperator(m_valueList.get())) - return false; - - value = m_valueList->current(); - } - - if (!srcList->length()) - return false; - - addProperty(CSSPropertySrc, srcList.release(), m_important); - return true; -} - -bool CSSParser::parseFilterRuleMix() -{ - if (m_valueList->size() > 2) - return false; - - RefPtr<CSSValueList> mixList = CSSValueList::createSpaceSeparated(); - - bool hasBlendMode = false; - bool hasAlphaCompositing = false; - CSSParserValue* value = m_valueList->current(); - while (value) { - RefPtr<CSSValue> mixValue; - if (!hasBlendMode && isBlendMode(value->id)) { - hasBlendMode = true; - mixValue = cssValuePool().createIdentifierValue(value->id); - } else if (!hasAlphaCompositing && isCompositeOperator(value->id)) { - hasAlphaCompositing = true; - mixValue = cssValuePool().createIdentifierValue(value->id); - } - - if (!mixValue) - return false; - - mixList->append(mixValue.release()); - value = m_valueList->next(); - } - - addProperty(CSSPropertyMix, mixList.release(), m_important); - return true; -} - -bool CSSParser::parseGeometry(CSSPropertyID propId, CSSParserValue* value, bool important) -{ - ASSERT(propId == CSSPropertyGeometry); - - // <geometry-shape> = grid(<integer>{1,2} || [ detached | attached ]?) - if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "grid(")) - return false; - - ASSERT(value->function->args); - - // grid() function should have from 1 to 3 arguments. - unsigned size = value->function->args->size(); - if (!size || size > 3) - return false; - - CSSParserValueList* gridParserValueList = value->function->args.get(); - CSSParserValue* gridParserValue = gridParserValueList->current(); - RefPtr<CSSValueList> geometryList = CSSValueList::createSpaceSeparated(); - - bool hasDimensions = false; - bool hasConnectivity = false; - - while (gridParserValue) { - if (hasDimensions && hasConnectivity) { - geometryList.release(); - return false; - } - - if (gridParserValue->id == CSSValueAttached || gridParserValue->id == CSSValueDetached) { - hasConnectivity = true; - geometryList->append(cssValuePool().createIdentifierValue(gridParserValue->id)); - gridParserValue = gridParserValueList->next(); - } else if (!hasDimensions && parseGridDimensions(gridParserValueList, geometryList)) { - hasDimensions = true; - gridParserValue = gridParserValueList->current(); - } else { - geometryList.release(); - return false; - } - } - - addProperty(propId, geometryList.release(), important); - return hasDimensions; -} - -bool CSSParser::parseGridDimensions(CSSParserValueList* args, RefPtr<CSSValueList>& gridValueList) -{ - ASSERT(args); - - // There must be at least one valid numeric value. - CSSParserValue* arg = args->current(); - if (!arg || !validUnit(arg, FPositiveInteger)) - return false; - - // A valid numeric value is parsed and then we move on. - gridValueList->append(createPrimitiveNumericValue(arg)); - arg = args->next(); - - // If the next argument is not numeric, we are done parsing the grid dimensions. - if (!arg || !validUnit(arg, FPositiveInteger)) - return true; - - // Commit the second numeric value we found. - gridValueList->append(createPrimitiveNumericValue(arg)); - args->next(); - return true; -} - -bool CSSParser::parseFilterRuleParameters() -{ - RefPtr<CSSValueList> paramsList = parseCustomFilterParameters(m_valueList.get()); - if (!paramsList) - return false; - - addProperty(CSSPropertyParameters, paramsList.release(), m_important); - return true; -} - -StyleRuleBase* CSSParser::createFilterRule(const CSSParserString& filterName) -{ - RefPtr<StyleRuleFilter> rule = StyleRuleFilter::create(filterName); - rule->setProperties(createStylePropertySet()); - clearProperties(); - StyleRuleFilter* result = rule.get(); - m_parsedRules.append(rule.release()); - processAndAddNewRuleToSourceTreeIfNeeded(); - return result; -} - -#endif // ENABLE(CSS_SHADERS) - -PassRefPtr<WebKitCSSFilterValue> CSSParser::parseBuiltinFilterArguments(CSSParserValueList* args, WebKitCSSFilterValue::FilterOperationType filterType) +RefPtr<WebKitCSSFilterValue> CSSParser::parseBuiltinFilterArguments(CSSParserValueList& args, WebKitCSSFilterValue::FilterOperationType filterType) { RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(filterType); - ASSERT(args); switch (filterType) { case WebKitCSSFilterValue::GrayscaleFilterOperation: @@ -9071,77 +9997,77 @@ PassRefPtr<WebKitCSSFilterValue> CSSParser::parseBuiltinFilterArguments(CSSParse case WebKitCSSFilterValue::OpacityFilterOperation: case WebKitCSSFilterValue::ContrastFilterOperation: { // One optional argument, 0-1 or 0%-100%, if missing use 100%. - if (args->size() > 1) - return 0; + if (args.size() > 1) + return nullptr; + + if (args.size()) { + ValueWithCalculation argumentWithCalculation(*args.current()); + if (!validateUnit(argumentWithCalculation, FNumber | FPercent | FNonNeg, CSSStrictMode)) + return nullptr; + + auto primitiveValue = createPrimitiveNumericValue(argumentWithCalculation); - if (args->size()) { - CSSParserValue* value = args->current(); - if (!validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode)) - return 0; - - double amount = value->fValue; - // Saturate and Contrast allow values over 100%. if (filterType != WebKitCSSFilterValue::SaturateFilterOperation && filterType != WebKitCSSFilterValue::ContrastFilterOperation) { - double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0; - if (amount > maxAllowed) - return 0; + double maxAllowed = primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0; + if (primitiveValue->getDoubleValue() > maxAllowed) + return nullptr; } - filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit))); + filterValue->append(WTFMove(primitiveValue)); } break; } case WebKitCSSFilterValue::BrightnessFilterOperation: { // One optional argument, if missing use 100%. - if (args->size() > 1) - return 0; + if (args.size() > 1) + return nullptr; - if (args->size()) { - CSSParserValue* value = args->current(); - if (!validUnit(value, FNumber | FPercent, CSSStrictMode)) - return 0; + if (args.size()) { + ValueWithCalculation argumentWithCalculation(*args.current()); + if (!validateUnit(argumentWithCalculation, FNumber | FPercent, CSSStrictMode)) + return nullptr; - filterValue->append(cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit))); + filterValue->append(createPrimitiveNumericValue(argumentWithCalculation)); } break; } case WebKitCSSFilterValue::HueRotateFilterOperation: { // hue-rotate() takes one optional angle. - if (args->size() > 1) - return 0; + if (args.size() > 1) + return nullptr; - if (args->size()) { - CSSParserValue* argument = args->current(); - if (!validUnit(argument, FAngle, CSSStrictMode)) - return 0; + if (args.size()) { + ValueWithCalculation argumentWithCalculation(*args.current()); + if (!validateUnit(argumentWithCalculation, FAngle, CSSStrictMode)) + return nullptr; - filterValue->append(createPrimitiveNumericValue(argument)); + filterValue->append(createPrimitiveNumericValue(argumentWithCalculation)); } break; } case WebKitCSSFilterValue::BlurFilterOperation: { // Blur takes a single length. Zero parameters are allowed. - if (args->size() > 1) - return 0; + if (args.size() > 1) + return nullptr; - if (args->size()) { - CSSParserValue* argument = args->current(); - if (!validUnit(argument, FLength | FNonNeg, CSSStrictMode)) - return 0; + if (args.size()) { + ValueWithCalculation argumentWithCalculation(*args.current()); + if (!validateUnit(argumentWithCalculation, FLength | FNonNeg, CSSStrictMode)) + return nullptr; - filterValue->append(createPrimitiveNumericValue(argument)); + filterValue->append(createPrimitiveNumericValue(argumentWithCalculation)); } break; } case WebKitCSSFilterValue::DropShadowFilterOperation: { // drop-shadow() takes a single shadow. - RefPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter); + RefPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyFilter); if (!shadowValueList || shadowValueList->length() != 1) - return 0; + return nullptr; - filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0)); + filterValue->append(*shadowValueList->itemWithoutBoundsCheck(0)); break; } default: @@ -9150,26 +10076,21 @@ PassRefPtr<WebKitCSSFilterValue> CSSParser::parseBuiltinFilterArguments(CSSParse return filterValue.release(); } -PassRefPtr<CSSValueList> CSSParser::parseFilter() +bool CSSParser::parseFilter(CSSParserValueList& valueList, RefPtr<CSSValue>& result) { - if (!m_valueList) - return 0; - // The filter is a list of functional primitives that specify individual operations. RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); - for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { + for (auto* value = valueList.current(); value; value = valueList.next()) { if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function)) - return 0; + return false; WebKitCSSFilterValue::FilterOperationType filterType = WebKitCSSFilterValue::UnknownFilterOperation; // See if the specified primitive is one we understand. if (value->unit == CSSPrimitiveValue::CSS_URI) { -#if ENABLE(SVG) RefPtr<WebKitCSSFilterValue> referenceFilterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::ReferenceFilterOperation); - list->append(referenceFilterValue); - referenceFilterValue->append(WebKitCSSSVGDocumentValue::create(value->string)); -#endif + referenceFilterValue->append(CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI)); + list->append(referenceFilterValue.releaseNonNull()); } else { const CSSParserString name = value->function->name; unsigned maximumArgumentCount = 1; @@ -9177,45 +10098,33 @@ PassRefPtr<CSSValueList> CSSParser::parseFilter() filterInfoForName(name, filterType, maximumArgumentCount); if (filterType == WebKitCSSFilterValue::UnknownFilterOperation) - return 0; + return false; -#if ENABLE(CSS_SHADERS) - if (filterType == WebKitCSSFilterValue::CustomFilterOperation) { - // Make sure parsing fails if custom filters are disabled. - if (!m_context.isCSSCustomFilterEnabled) - return 0; - - RefPtr<WebKitCSSFilterValue> filterValue = parseCustomFilterFunction(value); - if (!filterValue) - return 0; - list->append(filterValue.release()); - continue; - } -#endif CSSParserValueList* args = value->function->args.get(); if (!args) - return 0; + return false; - RefPtr<WebKitCSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType); + RefPtr<WebKitCSSFilterValue> filterValue = parseBuiltinFilterArguments(*args, filterType); if (!filterValue) - return 0; + return false; - list->append(filterValue); + list->append(filterValue.releaseNonNull()); } } - return list.release(); + result = list; + + return true; } -#endif #if ENABLE(CSS_REGIONS) static bool validFlowName(const String& flowName) { - return !(equalIgnoringCase(flowName, "auto") - || equalIgnoringCase(flowName, "default") - || equalIgnoringCase(flowName, "inherit") - || equalIgnoringCase(flowName, "initial") - || equalIgnoringCase(flowName, "none")); + return !(equalLettersIgnoringASCIICase(flowName, "auto") + || equalLettersIgnoringASCIICase(flowName, "default") + || equalLettersIgnoringASCIICase(flowName, "inherit") + || equalLettersIgnoringASCIICase(flowName, "initial") + || equalLettersIgnoringASCIICase(flowName, "none")); } #endif @@ -9229,21 +10138,7 @@ bool CSSParser::cssCompositingEnabled() const return m_context.isCSSCompositingEnabled; } -bool CSSParser::cssGridLayoutEnabled() const -{ - return m_context.isCSSGridLayoutEnabled; -} - #if ENABLE(CSS_REGIONS) -bool CSSParser::parseFlowThread(const String& flowName) -{ - setupParser("@-webkit-decls{-webkit-flow-into:", flowName, "}"); - cssyyparse(this); - - m_rule = 0; - - return ((m_parsedProperties.size() == 1) && (m_parsedProperties.first().id() == CSSPropertyWebkitFlowInto)); -} // none | <ident> bool CSSParser::parseFlowThread(CSSPropertyID propId, bool important) @@ -9262,7 +10157,7 @@ bool CSSParser::parseFlowThread(CSSPropertyID propId, bool important) return false; if (value->id == CSSValueNone) { - addProperty(propId, cssValuePool().createIdentifierValue(value->id), important); + addProperty(propId, CSSValuePool::singleton().createIdentifierValue(value->id), important); return true; } @@ -9270,9 +10165,9 @@ bool CSSParser::parseFlowThread(CSSPropertyID propId, bool important) if (!inputProperty.isEmpty()) { if (!validFlowName(inputProperty)) return false; - addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important); + addProperty(propId, CSSValuePool::singleton().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important); } else - addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important); + addProperty(propId, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important); return true; } @@ -9294,95 +10189,96 @@ bool CSSParser::parseRegionThread(CSSPropertyID propId, bool important) return false; if (value->id == CSSValueNone) - addProperty(propId, cssValuePool().createIdentifierValue(value->id), important); + addProperty(propId, CSSValuePool::singleton().createIdentifierValue(value->id), important); else { String inputProperty = String(value->string); if (!inputProperty.isEmpty()) { if (!validFlowName(inputProperty)) return false; - addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important); + addProperty(propId, CSSValuePool::singleton().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important); } else - addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important); + addProperty(propId, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important); } return true; } #endif -bool CSSParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3) +bool CSSParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtr<CSSPrimitiveValue>& value, RefPtr<CSSPrimitiveValue>& value2, RefPtr<CSSValue>& value3) { propId1 = propId; propId2 = propId; propId3 = propId; - if (propId == CSSPropertyWebkitTransformOrigin) { - propId1 = CSSPropertyWebkitTransformOriginX; - propId2 = CSSPropertyWebkitTransformOriginY; - propId3 = CSSPropertyWebkitTransformOriginZ; + if (propId == CSSPropertyTransformOrigin) { + propId1 = CSSPropertyTransformOriginX; + propId2 = CSSPropertyTransformOriginY; + propId3 = CSSPropertyTransformOriginZ; } switch (propId) { - case CSSPropertyWebkitTransformOrigin: - if (!parseTransformOriginShorthand(value, value2, value3)) - return false; - // parseTransformOriginShorthand advances the m_valueList pointer - break; - case CSSPropertyWebkitTransformOriginX: { - value = parseFillPositionX(m_valueList.get()); - if (value) - m_valueList->next(); - break; - } - case CSSPropertyWebkitTransformOriginY: { - value = parseFillPositionY(m_valueList.get()); - if (value) - m_valueList->next(); - break; - } - case CSSPropertyWebkitTransformOriginZ: { - if (validUnit(m_valueList->current(), FLength)) - value = createPrimitiveNumericValue(m_valueList->current()); - if (value) - m_valueList->next(); - break; - } - default: - ASSERT_NOT_REACHED(); + case CSSPropertyTransformOrigin: + if (!parseTransformOriginShorthand(value, value2, value3)) return false; + // parseTransformOriginShorthand advances the m_valueList pointer + break; + case CSSPropertyTransformOriginX: { + value = parsePositionX(*m_valueList); + if (value) + m_valueList->next(); + break; + } + case CSSPropertyTransformOriginY: { + value = parsePositionY(*m_valueList); + if (value) + m_valueList->next(); + break; + } + case CSSPropertyTransformOriginZ: { + ValueWithCalculation valueWithCalculation(*m_valueList->current()); + if (validateUnit(valueWithCalculation, FLength)) + value = createPrimitiveNumericValue(valueWithCalculation); + if (value) + m_valueList->next(); + break; + } + default: + ASSERT_NOT_REACHED(); + return false; } return value; } -bool CSSParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2) +bool CSSParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr<CSSPrimitiveValue>& value, RefPtr<CSSPrimitiveValue>& value2) { propId1 = propId; propId2 = propId; - if (propId == CSSPropertyWebkitPerspectiveOrigin) { - propId1 = CSSPropertyWebkitPerspectiveOriginX; - propId2 = CSSPropertyWebkitPerspectiveOriginY; + if (propId == CSSPropertyPerspectiveOrigin) { + propId1 = CSSPropertyPerspectiveOriginX; + propId2 = CSSPropertyPerspectiveOriginY; } switch (propId) { - case CSSPropertyWebkitPerspectiveOrigin: - if (m_valueList->size() > 2) - return false; - parse2ValuesFillPosition(m_valueList.get(), value, value2); - break; - case CSSPropertyWebkitPerspectiveOriginX: { - value = parseFillPositionX(m_valueList.get()); - if (value) - m_valueList->next(); - break; - } - case CSSPropertyWebkitPerspectiveOriginY: { - value = parseFillPositionY(m_valueList.get()); - if (value) - m_valueList->next(); - break; - } - default: - ASSERT_NOT_REACHED(); + case CSSPropertyPerspectiveOrigin: + if (m_valueList->size() > 2) return false; + parse2ValuesFillPosition(*m_valueList, value, value2); + break; + case CSSPropertyPerspectiveOriginX: { + value = parsePositionX(*m_valueList); + if (value) + m_valueList->next(); + break; + } + case CSSPropertyPerspectiveOriginY: { + value = parsePositionY(*m_valueList); + if (value) + m_valueList->next(); + break; + } + default: + ASSERT_NOT_REACHED(); + return false; } return value; @@ -9390,23 +10286,21 @@ bool CSSParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& prop void CSSParser::addTextDecorationProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important) { -#if ENABLE(CSS3_TEXT) // The text-decoration-line property takes priority over text-decoration, unless the latter has important priority set. - if (propId == CSSPropertyTextDecoration && !important && m_currentShorthand == CSSPropertyInvalid) { + if (propId == CSSPropertyTextDecoration && !important && !inShorthand()) { for (unsigned i = 0; i < m_parsedProperties.size(); ++i) { if (m_parsedProperties[i].id() == CSSPropertyWebkitTextDecorationLine) return; } } -#endif // CSS3_TEXT addProperty(propId, value, important); } bool CSSParser::parseTextDecoration(CSSPropertyID propId, bool important) { CSSParserValue* value = m_valueList->current(); - if (value->id == CSSValueNone) { - addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important); + if (value && value->id == CSSValueNone) { + addTextDecorationProperty(propId, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important); m_valueList->next(); return true; } @@ -9419,7 +10313,10 @@ bool CSSParser::parseTextDecoration(CSSPropertyID propId, bool important) case CSSValueLineThrough: case CSSValueOverline: case CSSValueUnderline: - list->append(cssValuePool().createIdentifierValue(value->id)); +#if ENABLE(LETTERPRESS) + case CSSValueWebkitLetterpress: +#endif + list->append(CSSValuePool::singleton().createIdentifierValue(value->id)); break; default: isValid = false; @@ -9429,7 +10326,8 @@ bool CSSParser::parseTextDecoration(CSSPropertyID propId, bool important) value = m_valueList->next(); } - if (list->length() && isValid) { + // Values are either valid or in shorthand scope. + if (list->length() && (isValid || inShorthand())) { addTextDecorationProperty(propId, list.release(), important); return true; } @@ -9437,28 +10335,46 @@ bool CSSParser::parseTextDecoration(CSSPropertyID propId, bool important) return false; } -#if ENABLE(CSS3_TEXT) +bool CSSParser::parseTextDecorationSkip(bool important) +{ + // The text-decoration-skip property has syntax "none | [ objects || spaces || ink || edges || box-decoration ]". + // However, only 'none' and 'ink' are implemented yet, so we will parse syntax "none | ink" for now. + CSSParserValue* value = m_valueList->current(); + do { + switch (value->id) { + case CSSValueNone: + case CSSValueAuto: + case CSSValueInk: + case CSSValueObjects: + addProperty(CSSPropertyWebkitTextDecorationSkip, CSSValuePool::singleton().createIdentifierValue(value->id), important); + return true; + default: + break; + } + } while ((value = m_valueList->next())); + return false; +} + bool CSSParser::parseTextUnderlinePosition(bool important) { // The text-underline-position property has sintax "auto | alphabetic | [ under || [ left | right ] ]". // However, values 'left' and 'right' are not implemented yet, so we will parse sintax // "auto | alphabetic | under" for now. - CSSParserValue* value = m_valueList->current(); - switch (value->id) { + CSSParserValue& value = *m_valueList->current(); + switch (value.id) { case CSSValueAuto: case CSSValueAlphabetic: case CSSValueUnder: if (m_valueList->next()) return false; - addProperty(CSSPropertyWebkitTextUnderlinePosition, cssValuePool().createIdentifierValue(value->id), important); + addProperty(CSSPropertyWebkitTextUnderlinePosition, CSSValuePool::singleton().createIdentifierValue(value.id), important); return true; default: break; } return false; } -#endif // CSS3_TEXT bool CSSParser::parseTextEmphasisStyle(bool important) { @@ -9471,7 +10387,7 @@ bool CSSParser::parseTextEmphasisStyle(bool important) if (value->unit == CSSPrimitiveValue::CSS_STRING) { if (fill || shape || (valueListSize != 1 && !inShorthand())) return false; - addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important); + addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(*value), important); m_valueList->next(); return true; } @@ -9479,7 +10395,7 @@ bool CSSParser::parseTextEmphasisStyle(bool important) if (value->id == CSSValueNone) { if (fill || shape || (valueListSize != 1 && !inShorthand())) return false; - addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important); + addProperty(CSSPropertyWebkitTextEmphasisStyle, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important); m_valueList->next(); return true; } @@ -9487,11 +10403,11 @@ bool CSSParser::parseTextEmphasisStyle(bool important) if (value->id == CSSValueOpen || value->id == CSSValueFilled) { if (fill) return false; - fill = cssValuePool().createIdentifierValue(value->id); + fill = CSSValuePool::singleton().createIdentifierValue(value->id); } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) { if (shape) return false; - shape = cssValuePool().createIdentifierValue(value->id); + shape = CSSValuePool::singleton().createIdentifierValue(value->id); } else if (!inShorthand()) return false; else @@ -9500,8 +10416,8 @@ bool CSSParser::parseTextEmphasisStyle(bool important) if (fill && shape) { RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated(); - parsedValues->append(fill.release()); - parsedValues->append(shape.release()); + parsedValues->append(fill.releaseNonNull()); + parsedValues->append(shape.releaseNonNull()); addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important); return true; } @@ -9517,7 +10433,53 @@ bool CSSParser::parseTextEmphasisStyle(bool important) return false; } -PassRefPtr<CSSValue> CSSParser::parseTextIndent() +bool CSSParser::parseTextEmphasisPosition(bool important) +{ + bool foundOverOrUnder = false; + CSSValueID overUnderValueID = CSSValueOver; + bool foundLeftOrRight = false; + CSSValueID leftRightValueID = CSSValueRight; + for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { + switch (value->id) { + case CSSValueOver: + if (foundOverOrUnder) + return false; + foundOverOrUnder = true; + overUnderValueID = CSSValueOver; + break; + case CSSValueUnder: + if (foundOverOrUnder) + return false; + foundOverOrUnder = true; + overUnderValueID = CSSValueUnder; + break; + case CSSValueLeft: + if (foundLeftOrRight) + return false; + foundLeftOrRight = true; + leftRightValueID = CSSValueLeft; + break; + case CSSValueRight: + if (foundLeftOrRight) + return false; + foundLeftOrRight = true; + leftRightValueID = CSSValueRight; + break; + default: + return false; + } + } + if (!foundOverOrUnder) + return false; + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(CSSValuePool::singleton().createIdentifierValue(overUnderValueID)); + if (foundLeftOrRight) + list->append(CSSValuePool::singleton().createIdentifierValue(leftRightValueID)); + addProperty(CSSPropertyWebkitTextEmphasisPosition, list, important); + return true; +} + +RefPtr<CSSValue> CSSParser::parseTextIndent() { // <length> | <percentage> | inherit when CSS3_TEXT is disabled. // [ <length> | <percentage> ] && [ -webkit-hanging || -webkit-each-line ]? | inherit when CSS3_TEXT is enabled. @@ -9530,31 +10492,76 @@ PassRefPtr<CSSValue> CSSParser::parseTextIndent() CSSParserValue* value = m_valueList->current(); while (value) { - if (!hasLengthOrPercentage && validUnit(value, FLength | FPercent)) { - list->append(createPrimitiveNumericValue(value)); + ValueWithCalculation valueWithCalculation(*value); + if (!hasLengthOrPercentage && validateUnit(valueWithCalculation, FLength | FPercent)) { + list->append(createPrimitiveNumericValue(valueWithCalculation)); hasLengthOrPercentage = true; } #if ENABLE(CSS3_TEXT) else if (!hasEachLine && value->id == CSSValueWebkitEachLine) { - list->append(cssValuePool().createIdentifierValue(CSSValueWebkitEachLine)); + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueWebkitEachLine)); hasEachLine = true; } else if (!hasHanging && value->id == CSSValueWebkitHanging) { - list->append(cssValuePool().createIdentifierValue(CSSValueWebkitHanging)); + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueWebkitHanging)); hasHanging = true; } #endif else - return 0; + return nullptr; value = m_valueList->next(); } if (!hasLengthOrPercentage) - return 0; + return nullptr; return list.release(); } +bool CSSParser::parseHangingPunctuation(bool important) +{ + CSSParserValue* value = m_valueList->current(); + if (value && value->id == CSSValueNone) { + addProperty(CSSPropertyHangingPunctuation, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important); + m_valueList->next(); + return true; + } + + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + bool isValid = true; + std::bitset<numCSSValueKeywords> seenValues; + while (isValid && value) { + if (seenValues[value->id] + || (value->id == CSSValueAllowEnd && seenValues[CSSValueForceEnd]) + || (value->id == CSSValueForceEnd && seenValues[CSSValueAllowEnd])) { + isValid = false; + break; + } + switch (value->id) { + case CSSValueAllowEnd: + case CSSValueFirst: + case CSSValueForceEnd: + case CSSValueLast: + list->append(CSSValuePool::singleton().createIdentifierValue(value->id)); + seenValues.set(value->id); + break; + default: + isValid = false; + break; + } + if (isValid) + value = m_valueList->next(); + } + + // Values are either valid or in shorthand scope. + if (list->length() && isValid) { + addProperty(CSSPropertyHangingPunctuation, list.release(), important); + return true; + } + + return false; +} + bool CSSParser::parseLineBoxContain(bool important) { LineBoxContain lineBoxContain = LineBoxContainNone; @@ -9584,6 +10591,10 @@ bool CSSParser::parseLineBoxContain(bool important) if (lineBoxContain & LineBoxContainInlineBox) return false; lineBoxContain |= LineBoxContainInlineBox; + } else if (value->id == CSSValueInitialLetter) { + if (lineBoxContain & LineBoxContainInitialLetter) + return false; + lineBoxContain |= LineBoxContainInitialLetter; } else return false; } @@ -9595,25 +10606,23 @@ bool CSSParser::parseLineBoxContain(bool important) return true; } -bool CSSParser::parseFontFeatureTag(CSSValueList* settings) +bool CSSParser::parseFontFeatureTag(CSSValueList& settings) { - // Feature tag name consists of 4-letter characters. - static const unsigned tagNameLength = 4; - CSSParserValue* value = m_valueList->current(); // Feature tag name comes first if (value->unit != CSSPrimitiveValue::CSS_STRING) return false; - if (value->string.length() != tagNameLength) + FontFeatureTag tag; + if (value->string.length() != tag.size()) return false; - for (unsigned i = 0; i < tagNameLength; ++i) { + for (unsigned i = 0; i < tag.size(); ++i) { // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification. UChar character = value->string[i]; if (character < 0x20 || character > 0x7E) return false; + tag[i] = toASCIILower(character); } - String tag = value->string; int tagValue = 1; // Feature tag values could follow: <integer> | on | off value = m_valueList->next(); @@ -9628,22 +10637,22 @@ bool CSSParser::parseFontFeatureTag(CSSValueList* settings) m_valueList->next(); } } - settings->append(FontFeatureValue::create(tag, tagValue)); + settings.append(CSSFontFeatureValue::create(WTFMove(tag), tagValue)); return true; } bool CSSParser::parseFontFeatureSettings(bool important) { if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) { - RefPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal); + RefPtr<CSSPrimitiveValue> normalValue = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); m_valueList->next(); - addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important); + addProperty(CSSPropertyFontFeatureSettings, normalValue.release(), important); return true; } RefPtr<CSSValueList> settings = CSSValueList::createCommaSeparated(); for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { - if (!parseFontFeatureTag(settings.get())) + if (!parseFontFeatureTag(*settings)) return false; // If the list isn't parsed fully, the current value should be comma. @@ -9652,18 +10661,19 @@ bool CSSParser::parseFontFeatureSettings(bool important) return false; } if (settings->length()) { - addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important); + addProperty(CSSPropertyFontFeatureSettings, settings.release(), important); return true; } return false; } -bool CSSParser::parseFontVariantLigatures(bool important) +bool CSSParser::parseFontVariantLigatures(bool important, bool unknownIsFailure, bool implicit) { - RefPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated(); - bool sawCommonLigaturesValue = false; - bool sawDiscretionaryLigaturesValue = false; - bool sawHistoricalLigaturesValue = false; + auto values = CSSValueList::createSpaceSeparated(); + FontVariantLigatures commonLigatures = FontVariantLigatures::Normal; + FontVariantLigatures discretionaryLigatures = FontVariantLigatures::Normal; + FontVariantLigatures historicalLigatures = FontVariantLigatures::Normal; + FontVariantLigatures contextualAlternates = FontVariantLigatures::Normal; for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { if (value->unit != CSSPrimitiveValue::CSS_IDENT) @@ -9671,55 +10681,471 @@ bool CSSParser::parseFontVariantLigatures(bool important) switch (value->id) { case CSSValueNoCommonLigatures: + commonLigatures = FontVariantLigatures::No; + break; case CSSValueCommonLigatures: - if (sawCommonLigaturesValue) - return false; - sawCommonLigaturesValue = true; - ligatureValues->append(cssValuePool().createIdentifierValue(value->id)); + commonLigatures = FontVariantLigatures::Yes; break; case CSSValueNoDiscretionaryLigatures: + discretionaryLigatures = FontVariantLigatures::No; + break; case CSSValueDiscretionaryLigatures: - if (sawDiscretionaryLigaturesValue) - return false; - sawDiscretionaryLigaturesValue = true; - ligatureValues->append(cssValuePool().createIdentifierValue(value->id)); + discretionaryLigatures = FontVariantLigatures::Yes; break; case CSSValueNoHistoricalLigatures: + historicalLigatures = FontVariantLigatures::No; + break; case CSSValueHistoricalLigatures: - if (sawHistoricalLigaturesValue) + historicalLigatures = FontVariantLigatures::Yes; + break; + case CSSValueContextual: + contextualAlternates = FontVariantLigatures::Yes; + break; + case CSSValueNoContextual: + contextualAlternates = FontVariantLigatures::No; + break; + default: + if (unknownIsFailure) return false; - sawHistoricalLigaturesValue = true; - ligatureValues->append(cssValuePool().createIdentifierValue(value->id)); + continue; + } + } + + switch (commonLigatures) { + case FontVariantLigatures::Normal: + break; + case FontVariantLigatures::Yes: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueCommonLigatures)); + break; + case FontVariantLigatures::No: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueNoCommonLigatures)); + break; + } + + switch (discretionaryLigatures) { + case FontVariantLigatures::Normal: + break; + case FontVariantLigatures::Yes: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueDiscretionaryLigatures)); + break; + case FontVariantLigatures::No: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueNoDiscretionaryLigatures)); + break; + } + + switch (historicalLigatures) { + case FontVariantLigatures::Normal: + break; + case FontVariantLigatures::Yes: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueHistoricalLigatures)); + break; + case FontVariantLigatures::No: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueNoHistoricalLigatures)); + break; + } + + switch (contextualAlternates) { + case FontVariantLigatures::Normal: + break; + case FontVariantLigatures::Yes: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueContextual)); + break; + case FontVariantLigatures::No: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueNoContextual)); + break; + } + + if (!values->length()) + return !unknownIsFailure; + + addProperty(CSSPropertyFontVariantLigatures, WTFMove(values), important, implicit); + return true; +} + +bool CSSParser::parseFontVariantNumeric(bool important, bool unknownIsFailure, bool implicit) +{ + auto values = CSSValueList::createSpaceSeparated(); + FontVariantNumericFigure figure = FontVariantNumericFigure::Normal; + FontVariantNumericSpacing spacing = FontVariantNumericSpacing::Normal; + FontVariantNumericFraction fraction = FontVariantNumericFraction::Normal; + FontVariantNumericOrdinal ordinal = FontVariantNumericOrdinal::Normal; + FontVariantNumericSlashedZero slashedZero = FontVariantNumericSlashedZero::Normal; + + for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { + if (value->unit != CSSPrimitiveValue::CSS_IDENT) + return false; + + switch (value->id) { + case CSSValueLiningNums: + figure = FontVariantNumericFigure::LiningNumbers; + break; + case CSSValueOldstyleNums: + figure = FontVariantNumericFigure::OldStyleNumbers; + break; + case CSSValueProportionalNums: + spacing = FontVariantNumericSpacing::ProportionalNumbers; + break; + case CSSValueTabularNums: + spacing = FontVariantNumericSpacing::TabularNumbers; + break; + case CSSValueDiagonalFractions: + fraction = FontVariantNumericFraction::DiagonalFractions; + break; + case CSSValueStackedFractions: + fraction = FontVariantNumericFraction::StackedFractions; + break; + case CSSValueOrdinal: + ordinal = FontVariantNumericOrdinal::Yes; + break; + case CSSValueSlashedZero: + slashedZero = FontVariantNumericSlashedZero::Yes; break; default: + if (unknownIsFailure) + return false; + continue; + } + } + + switch (figure) { + case FontVariantNumericFigure::Normal: + break; + case FontVariantNumericFigure::LiningNumbers: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueLiningNums)); + break; + case FontVariantNumericFigure::OldStyleNumbers: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueOldstyleNums)); + break; + } + + switch (spacing) { + case FontVariantNumericSpacing::Normal: + break; + case FontVariantNumericSpacing::ProportionalNumbers: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueProportionalNums)); + break; + case FontVariantNumericSpacing::TabularNumbers: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueTabularNums)); + break; + } + + switch (fraction) { + case FontVariantNumericFraction::Normal: + break; + case FontVariantNumericFraction::DiagonalFractions: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueDiagonalFractions)); + break; + case FontVariantNumericFraction::StackedFractions: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueStackedFractions)); + break; + } + + switch (ordinal) { + case FontVariantNumericOrdinal::Normal: + break; + case FontVariantNumericOrdinal::Yes: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueOrdinal)); + break; + } + + switch (slashedZero) { + case FontVariantNumericSlashedZero::Normal: + break; + case FontVariantNumericSlashedZero::Yes: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueSlashedZero)); + break; + } + + if (!values->length()) + return !unknownIsFailure; + + addProperty(CSSPropertyFontVariantNumeric, WTFMove(values), important, implicit); + return true; +} + +bool CSSParser::parseFontVariantEastAsian(bool important, bool unknownIsFailure, bool implicit) +{ + auto values = CSSValueList::createSpaceSeparated(); + FontVariantEastAsianVariant variant = FontVariantEastAsianVariant::Normal; + FontVariantEastAsianWidth width = FontVariantEastAsianWidth::Normal; + FontVariantEastAsianRuby ruby = FontVariantEastAsianRuby::Normal; + + for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { + if (value->unit != CSSPrimitiveValue::CSS_IDENT) return false; + + switch (value->id) { + case CSSValueJis78: + variant = FontVariantEastAsianVariant::Jis78; + break; + case CSSValueJis83: + variant = FontVariantEastAsianVariant::Jis83; + break; + case CSSValueJis90: + variant = FontVariantEastAsianVariant::Jis90; + break; + case CSSValueJis04: + variant = FontVariantEastAsianVariant::Jis04; + break; + case CSSValueSimplified: + variant = FontVariantEastAsianVariant::Simplified; + break; + case CSSValueTraditional: + variant = FontVariantEastAsianVariant::Traditional; + break; + case CSSValueFullWidth: + width = FontVariantEastAsianWidth::Full; + break; + case CSSValueProportionalWidth: + width = FontVariantEastAsianWidth::Proportional; + break; + case CSSValueRuby: + ruby = FontVariantEastAsianRuby::Yes; + break; + default: + if (unknownIsFailure) + return false; + continue; } } - if (!ligatureValues->length()) + switch (variant) { + case FontVariantEastAsianVariant::Normal: + break; + case FontVariantEastAsianVariant::Jis78: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueJis78)); + break; + case FontVariantEastAsianVariant::Jis83: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueJis83)); + break; + case FontVariantEastAsianVariant::Jis90: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueJis90)); + break; + case FontVariantEastAsianVariant::Jis04: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueJis04)); + break; + case FontVariantEastAsianVariant::Simplified: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueSimplified)); + break; + case FontVariantEastAsianVariant::Traditional: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueTraditional)); + break; + } + + switch (width) { + case FontVariantEastAsianWidth::Normal: + break; + case FontVariantEastAsianWidth::Full: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueFullWidth)); + break; + case FontVariantEastAsianWidth::Proportional: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueProportionalWidth)); + break; + } + + switch (ruby) { + case FontVariantEastAsianRuby::Normal: + break; + case FontVariantEastAsianRuby::Yes: + values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueRuby)); + } + + if (!values->length()) + return !unknownIsFailure; + + addProperty(CSSPropertyFontVariantEastAsian, WTFMove(values), important, implicit); + return true; +} + +bool CSSParser::parseFontVariant(bool important) +{ + ShorthandScope scope(this, CSSPropertyFontVariant); + if (!parseFontVariantLigatures(important, false, false)) + return false; + m_valueList->setCurrentIndex(0); + if (!parseFontVariantNumeric(important, false, false)) + return false; + m_valueList->setCurrentIndex(0); + if (!parseFontVariantEastAsian(important, false, false)) return false; + m_valueList->setCurrentIndex(0); + + FontVariantPosition position = FontVariantPosition::Normal; + FontVariantCaps caps = FontVariantCaps::Normal; + FontVariantAlternates alternates = FontVariantAlternates::Normal; + + for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { + if (value->unit != CSSPrimitiveValue::CSS_IDENT) + return false; + + switch (value->id) { + case CSSValueNoCommonLigatures: + case CSSValueCommonLigatures: + case CSSValueNoDiscretionaryLigatures: + case CSSValueDiscretionaryLigatures: + case CSSValueNoHistoricalLigatures: + case CSSValueHistoricalLigatures: + case CSSValueContextual: + case CSSValueNoContextual: + case CSSValueLiningNums: + case CSSValueOldstyleNums: + case CSSValueProportionalNums: + case CSSValueTabularNums: + case CSSValueDiagonalFractions: + case CSSValueStackedFractions: + case CSSValueOrdinal: + case CSSValueSlashedZero: + case CSSValueJis78: + case CSSValueJis83: + case CSSValueJis90: + case CSSValueJis04: + case CSSValueSimplified: + case CSSValueTraditional: + case CSSValueFullWidth: + case CSSValueProportionalWidth: + case CSSValueRuby: + break; + case CSSValueSub: + position = FontVariantPosition::Subscript; + break; + case CSSValueSuper: + position = FontVariantPosition::Superscript; + break; + case CSSValueSmallCaps: + caps = FontVariantCaps::Small; + break; + case CSSValueAllSmallCaps: + caps = FontVariantCaps::AllSmall; + break; + case CSSValuePetiteCaps: + caps = FontVariantCaps::Petite; + break; + case CSSValueAllPetiteCaps: + caps = FontVariantCaps::AllPetite; + break; + case CSSValueUnicase: + caps = FontVariantCaps::Unicase; + break; + case CSSValueTitlingCaps: + caps = FontVariantCaps::Titling; + break; + case CSSValueHistoricalForms: + alternates = FontVariantAlternates::HistoricalForms; + break; + default: + return false; + } + } + + switch (position) { + case FontVariantPosition::Normal: + break; + case FontVariantPosition::Subscript: + addProperty(CSSPropertyFontVariantPosition, CSSValuePool::singleton().createIdentifierValue(CSSValueSub), important, false); + break; + case FontVariantPosition::Superscript: + addProperty(CSSPropertyFontVariantPosition, CSSValuePool::singleton().createIdentifierValue(CSSValueSuper), important, false); + break; + } + + switch (caps) { + case FontVariantCaps::Normal: + break; + case FontVariantCaps::Small: + addProperty(CSSPropertyFontVariantCaps, CSSValuePool::singleton().createIdentifierValue(CSSValueSmallCaps), important, false); + break; + case FontVariantCaps::AllSmall: + addProperty(CSSPropertyFontVariantCaps, CSSValuePool::singleton().createIdentifierValue(CSSValueAllSmallCaps), important, false); + break; + case FontVariantCaps::Petite: + addProperty(CSSPropertyFontVariantCaps, CSSValuePool::singleton().createIdentifierValue(CSSValuePetiteCaps), important, false); + break; + case FontVariantCaps::AllPetite: + addProperty(CSSPropertyFontVariantCaps, CSSValuePool::singleton().createIdentifierValue(CSSValueAllPetiteCaps), important, false); + break; + case FontVariantCaps::Unicase: + addProperty(CSSPropertyFontVariantCaps, CSSValuePool::singleton().createIdentifierValue(CSSValueUnicase), important, false); + break; + case FontVariantCaps::Titling: + addProperty(CSSPropertyFontVariantCaps, CSSValuePool::singleton().createIdentifierValue(CSSValueTitlingCaps), important, false); + break; + } + + switch (alternates) { + case FontVariantAlternates::Normal: + break; + case FontVariantAlternates::HistoricalForms: + addProperty(CSSPropertyFontVariantAlternates, CSSValuePool::singleton().createIdentifierValue(CSSValueHistoricalForms), important, false); + break; + } - addProperty(CSSPropertyWebkitFontVariantLigatures, ligatureValues.release(), important); return true; } -bool CSSParser::parseCalculation(CSSParserValue* value, CalculationPermittedValueRange range) +static inline bool isValidWillChangeAnimatableFeature(const CSSParserValue& value) { - ASSERT(isCalculation(value)); - - CSSParserValueList* args = value->function->args.get(); - if (!args || !args->size()) + if (value.id == CSSValueNone || value.id == CSSValueAuto || value.id == CSSValueAll) return false; - ASSERT(!m_parsedCalculation); - m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range); - - if (!m_parsedCalculation) + if (valueIsCSSKeyword(value)) return false; - + + if (cssPropertyID(value.string) == CSSPropertyWillChange) + return false; + return true; } +bool CSSParser::parseWillChange(bool important) +{ + RefPtr<CSSValueList> willChangePropertyValues = CSSValueList::createCommaSeparated(); + + bool expectComma = false; + for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { + if (expectComma) { + if (!isComma(value)) + return false; + + expectComma = false; + continue; + } + + if (value->unit != CSSPrimitiveValue::CSS_IDENT) + return false; + + if (!isValidWillChangeAnimatableFeature(*value)) + return false; + + RefPtr<CSSValue> cssValue; + if (value->id == CSSValueScrollPosition || value->id == CSSValueContents) + cssValue = CSSValuePool::singleton().createIdentifierValue(value->id); + else { + CSSPropertyID propertyID = cssPropertyID(value->string); + if (propertyID != CSSPropertyInvalid) + cssValue = CSSValuePool::singleton().createIdentifierValue(propertyID); + else // This might be a property we don't support. + cssValue = createPrimitiveStringValue(*value); + } + + willChangePropertyValues->append(cssValue.releaseNonNull()); + expectComma = true; + } + + addProperty(CSSPropertyWillChange, willChangePropertyValues.release(), important); + return true; +} + +RefPtr<CSSCalcValue> CSSParser::parseCalculation(CSSParserValue& value, CalculationPermittedValueRange range) +{ + ASSERT(isCalculation(value)); + + CSSParserValueList* args = value.function->args.get(); + if (!args || !args->size()) + return nullptr; + + return CSSCalcValue::create(value.function->name, *args, range); +} + #define END_TOKEN 0 #include "CSSGrammar.h" @@ -9737,7 +11163,7 @@ enum CharacterType { CharacterOther, CharacterNull, CharacterWhiteSpace, - CharacterEndMediaQuery, + CharacterEndConditionQuery, CharacterEndNthChild, CharacterQuote, CharacterExclamationMark, @@ -9816,7 +11242,7 @@ static const CharacterType typesOfASCIICharacters[128] = { /* 56 - 8 */ CharacterNumber, /* 57 - 9 */ CharacterNumber, /* 58 - : */ CharacterOther, -/* 59 - ; */ CharacterEndMediaQuery, +/* 59 - ; */ CharacterEndConditionQuery, /* 60 - < */ CharacterLess, /* 61 - = */ CharacterOther, /* 62 - > */ CharacterOther, @@ -9880,7 +11306,7 @@ static const CharacterType typesOfASCIICharacters[128] = { /* 120 - x */ CharacterIdentifierStart, /* 121 - y */ CharacterIdentifierStart, /* 122 - z */ CharacterIdentifierStart, -/* 123 - { */ CharacterEndMediaQuery, +/* 123 - { */ CharacterEndConditionQuery, /* 124 - | */ CharacterVerticalBar, /* 125 - } */ CharacterOther, /* 126 - ~ */ CharacterTilde, @@ -9915,6 +11341,13 @@ static inline bool isIdentifierStartAfterDash(CharacterType* currentCharacter) } template <typename CharacterType> +static inline bool isCustomPropertyIdentifier(CharacterType* currentCharacter) +{ + return isASCIIAlpha(currentCharacter[0]) || currentCharacter[0] == '_' || currentCharacter[0] >= 128 + || (currentCharacter[0] == '\\' && isCSSEscape(currentCharacter[1])); +} + +template <typename CharacterType> static inline bool isEqualToCSSIdentifier(CharacterType* cssString, const char* constantString) { // Compare an character memory data with a zero terminated string. @@ -9948,7 +11381,7 @@ static CharacterType* checkAndSkipEscape(CharacterType* currentCharacter) ++currentCharacter; if (!isCSSEscape(*currentCharacter)) - return 0; + return nullptr; if (isASCIIHexDigit(*currentCharacter)) { int length = 6; @@ -9996,7 +11429,7 @@ inline UChar*& CSSParser::currentCharacter<UChar>() UChar*& CSSParser::currentCharacter16() { if (!m_currentCharacter16) { - m_dataStart16 = adoptArrayPtr(new UChar[m_length]); + m_dataStart16 = std::make_unique<UChar[]>(m_length); m_currentCharacter16 = m_dataStart16.get(); } @@ -10019,10 +11452,19 @@ CSSParser::Location CSSParser::currentLocation() { Location location; location.lineNumber = m_tokenStartLineNumber; + location.columnNumber = m_tokenStartColumnNumber; + + ASSERT(location.lineNumber >= 0); + ASSERT(location.columnNumber >= 0); + + if (location.lineNumber == m_sheetStartLineNumber) + location.columnNumber += m_sheetStartColumnNumber; + if (is8BitSource()) location.token.init(tokenStart<LChar>(), currentCharacter<LChar>() - tokenStart<LChar>()); else location.token.init(tokenStart<UChar>(), currentCharacter<UChar>() - tokenStart<UChar>()); + return location; } @@ -10051,7 +11493,7 @@ static inline CharacterType* checkAndSkipString(CharacterType* currentCharacter, } if (UNLIKELY(*currentCharacter <= '\r' && (*currentCharacter == '\n' || (*currentCharacter | 0x1) == '\r'))) { // String parsing is failed for character '\n', '\f' or '\r'. - return 0; + return nullptr; } if (LIKELY(currentCharacter[0] != '\\')) @@ -10063,7 +11505,7 @@ static inline CharacterType* checkAndSkipString(CharacterType* currentCharacter, else { currentCharacter = checkAndSkipEscape(currentCharacter); if (!currentCharacter) - return 0; + return nullptr; } } } @@ -10084,9 +11526,8 @@ unsigned CSSParser::parseEscape(CharacterType*& src) unicode = (unicode << 4) + toASCIIHexValue(*src++); } while (--length && isASCIIHexDigit(*src)); - // Characters above 0x10ffff are not handled. - if (unicode > 0x10ffff) - unicode = 0xfffd; + if (unicode > UCHAR_MAX_VALUE) + unicode = replacementCharacter; // Optional space after the escape sequence. if (isHTMLSpace(*src)) @@ -10145,10 +11586,6 @@ inline bool CSSParser::parseIdentifierInternal(SrcCharacterType*& src, DestChara template <typename CharacterType> inline void CSSParser::parseIdentifier(CharacterType*& result, CSSParserString& resultString, bool& hasEscape) { - // If a valid identifier start is found, we can safely - // parse the identifier until the next invalid character. - ASSERT(isIdentifierStart<CharacterType>()); - CharacterType* start = currentCharacter<CharacterType>(); if (UNLIKELY(!parseIdentifierInternal(currentCharacter<CharacterType>(), result, hasEscape))) { // Found an escape we couldn't handle with 8 bits, copy what has been recognized and continue @@ -10156,13 +11593,14 @@ inline void CSSParser::parseIdentifier(CharacterType*& result, CSSParserString& UChar*& result16 = currentCharacter16(); UChar* start16 = result16; int i = 0; - for (; i < result - start; i++) + for (; i < result - start; ++i) result16[i] = start[i]; result16 += i; parseIdentifierInternal(currentCharacter<CharacterType>(), result16, hasEscape); + result += result16 - start16; resultString.init(start16, result16 - start16); return; @@ -10217,7 +11655,7 @@ inline void CSSParser::parseString(CharacterType*& result, CSSParserString& resu UChar*& result16 = currentCharacter16(); UChar* start16 = result16; int i = 0; - for (; i < result - start; i++) + for (; i < result - start; ++i) result16[i] = start[i]; result16 += i; @@ -10399,12 +11837,22 @@ inline bool CSSParser::detectFunctionTypeToken(int length) m_token = URI; return true; } + if (isASCIIAlphaCaselessEqual(name[0], 'v') && isASCIIAlphaCaselessEqual(name[1], 'a') && isASCIIAlphaCaselessEqual(name[2], 'r')) { + m_token = VARFUNCTION; + return true; + } #if ENABLE(VIDEO_TRACK) if (isASCIIAlphaCaselessEqual(name[0], 'c') && isASCIIAlphaCaselessEqual(name[1], 'u') && isASCIIAlphaCaselessEqual(name[2], 'e')) { m_token = CUEFUNCTION; return true; } #endif +#if ENABLE(CSS_SELECTORS_LEVEL4) + if (isASCIIAlphaCaselessEqual(name[0], 'd') && isASCIIAlphaCaselessEqual(name[1], 'i') && isASCIIAlphaCaselessEqual(name[2], 'r')) { + m_token = DIRFUNCTION; + return true; + } +#endif return false; case 4: @@ -10412,10 +11860,28 @@ inline bool CSSParser::detectFunctionTypeToken(int length) m_token = CALCFUNCTION; return true; } + if (isEqualToCSSIdentifier(name, "lang")) { + m_token = LANGFUNCTION; + return true; + } +#if ENABLE(CSS_SELECTORS_LEVEL4) + if (isEqualToCSSIdentifier(name, "role")) { + m_token = ROLEFUNCTION; + return true; + } +#endif + return false; + + case 7: + if (isEqualToCSSIdentifier(name, "matches")) { + m_token = MATCHESFUNCTION; + return true; + } return false; case 9: if (isEqualToCSSIdentifier(name, "nth-child")) { + m_token = NTHCHILDFUNCTIONS; m_parsingMode = NthChildMode; return true; } @@ -10430,6 +11896,7 @@ inline bool CSSParser::detectFunctionTypeToken(int length) case 14: if (isEqualToCSSIdentifier(name, "nth-last-child")) { + m_token = NTHCHILDFUNCTIONS; m_parsingMode = NthChildMode; return true; } @@ -10505,6 +11972,10 @@ inline void CSSParser::detectNumberToken(CharacterType* type, int length) } return; + case 'f': + if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'r')) + m_token = FR; + return; case 'g': if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'r') && isASCIIAlphaCaselessEqual(type[2], 'a') && isASCIIAlphaCaselessEqual(type[3], 'd')) @@ -10599,16 +12070,8 @@ inline void CSSParser::detectDashToken(int length) m_token = MINFUNCTION; else if (isASCIIAlphaCaselessEqual(name[10], 'x') && isEqualToCSSIdentifier(name + 1, "webkit-ma")) m_token = MAXFUNCTION; -#if ENABLE(CSS_VARIABLES) - else if (cssVariablesEnabled() && isASCIIAlphaCaselessEqual(name[10], 'r') && isEqualToCSSIdentifier(name + 1, "webkit-va")) - m_token = VARFUNCTION; -#endif } else if (length == 12 && isEqualToCSSIdentifier(name + 1, "webkit-calc")) m_token = CALCFUNCTION; -#if ENABLE(SHADOW_DOM) - else if (length == 19 && isEqualToCSSIdentifier(name + 1, "webkit-distributed")) - m_token = DISTRIBUTEDFUNCTION; -#endif } template <typename CharacterType> @@ -10662,13 +12125,6 @@ inline void CSSParser::detectAtToken(int length, bool hasEscape) m_token = FONT_FACE_SYM; return; -#if ENABLE(SHADOW_DOM) - case 'h': - if (length == 5 && isEqualToCSSIdentifier(name + 2, "ost")) - m_token = HOST_SYM; - return; -#endif - case 'i': if (length == 7 && isEqualToCSSIdentifier(name + 2, "mport")) { m_parsingMode = MediaQueryMode; @@ -10676,6 +12132,13 @@ inline void CSSParser::detectAtToken(int length, bool hasEscape) } return; + case 'k': + if (length == 10 && isEqualToCSSIdentifier(name + 2, "eyframes")) + m_token = KEYFRAMES_SYM; + else if (length == 14 && !hasEscape && isEqualToCSSIdentifier(name + 2, "eyframe-rule")) + m_token = KEYFRAME_RULE_SYM; + return; + case 'l': if (hasEscape) return; @@ -10725,14 +12188,12 @@ inline void CSSParser::detectAtToken(int length, bool hasEscape) } return; -#if ENABLE(CSS3_CONDITIONAL_RULES) case 's': if (length == 9 && isEqualToCSSIdentifier(name + 2, "upports")) { m_parsingMode = SupportsMode; m_token = SUPPORTS_SYM; } return; -#endif case 't': if (hasEscape) @@ -10789,16 +12250,8 @@ inline void CSSParser::detectAtToken(int length, bool hasEscape) return; #if ENABLE(CSS_REGIONS) - if (isASCIIAlphaCaselessEqual(name[14], 'n') && isEqualToCSSIdentifier(name + 2, "webkit-regio")) { + if (isASCIIAlphaCaselessEqual(name[14], 'n') && isEqualToCSSIdentifier(name + 2, "webkit-regio")) m_token = WEBKIT_REGION_RULE_SYM; - return; - } -#endif -#if ENABLE(CSS_SHADERS) - if (isASCIIAlphaCaselessEqual(name[14], 'r') && isEqualToCSSIdentifier(name + 2, "webkit-filte")) { - m_token = WEBKIT_FILTER_RULE_SYM; - return; - } #endif return; @@ -10816,7 +12269,9 @@ inline void CSSParser::detectAtToken(int length, bool hasEscape) case 18: if (isEqualToCSSIdentifier(name + 2, "webkit-keyframes")) - m_token = WEBKIT_KEYFRAMES_SYM; + m_token = KEYFRAMES_SYM; + else if (isEqualToCSSIdentifier(name + 2, "webkit-sizesattr")) + m_token = WEBKIT_SIZESATTR_SYM; return; case 19: @@ -10828,22 +12283,19 @@ inline void CSSParser::detectAtToken(int length, bool hasEscape) case 22: if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-keyframe-rule")) - m_token = WEBKIT_KEYFRAME_RULE_SYM; + m_token = KEYFRAME_RULE_SYM; return; case 27: -#if ENABLE(CSS3_CONDITIONAL_RULES) if (isEqualToCSSIdentifier(name + 2, "webkit-supports-condition")) { m_parsingMode = SupportsMode; m_token = WEBKIT_SUPPORTS_CONDITION_SYM; } -#endif return; } } } -#if ENABLE(CSS3_CONDITIONAL_RULES) template <typename CharacterType> inline void CSSParser::detectSupportsToken(int length) { @@ -10860,7 +12312,6 @@ inline void CSSParser::detectSupportsToken(int length) m_token = SUPPORTS_NOT; } } -#endif template <typename SrcCharacterType> int CSSParser::realLex(void* yylvalWithoutType) @@ -10882,18 +12333,20 @@ restartAfterComment: result = currentCharacter<SrcCharacterType>(); setTokenStart(result); m_tokenStartLineNumber = m_lineNumber; + m_tokenStartColumnNumber = tokenStartOffset() - m_columnOffsetForLine; m_token = *currentCharacter<SrcCharacterType>(); ++currentCharacter<SrcCharacterType>(); switch ((m_token <= 127) ? typesOfASCIICharacters[m_token] : CharacterIdentifierStart) { case CharacterCaselessU: - if (UNLIKELY(*currentCharacter<SrcCharacterType>() == '+')) + if (UNLIKELY(*currentCharacter<SrcCharacterType>() == '+')) { if (parseUnicodeRange<SrcCharacterType>()) { m_token = UNICODERANGE; yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>()); break; } - // Fall through to CharacterIdentifierStart. + } + FALLTHROUGH; // To CharacterIdentifierStart. case CharacterIdentifierStart: --currentCharacter<SrcCharacterType>(); @@ -10901,13 +12354,11 @@ restartAfterComment: m_token = IDENT; if (UNLIKELY(*currentCharacter<SrcCharacterType>() == '(')) { -#if ENABLE(CSS3_CONDITIONAL_RULES) if (m_parsingMode == SupportsMode && !hasEscape) { detectSupportsToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>()); if (m_token != IDENT) break; } -#endif m_token = FUNCTION; bool shouldSkipParenthesis = true; if (!hasEscape) { @@ -10937,10 +12388,8 @@ restartAfterComment: } else if (UNLIKELY(m_parsingMode != NormalMode) && !hasEscape) { if (m_parsingMode == MediaQueryMode) detectMediaQueryToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>()); -#if ENABLE(CSS3_CONDITIONAL_RULES) else if (m_parsingMode == SupportsMode) detectSupportsToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>()); -#endif else if (m_parsingMode == NthChildMode && isASCIIAlphaCaselessEqual(tokenStart<SrcCharacterType>()[0], 'n')) { if (result - tokenStart<SrcCharacterType>() == 1) { // String "n" is IDENT but "n+1" is NTH. @@ -10963,12 +12412,16 @@ restartAfterComment: } } } + if (m_parsingMode == NthChildMode && m_token == IDENT && yylval->string.length() == 2 && equalLettersIgnoringASCIICase(yylval->string, "of")) { + m_parsingMode = NormalMode; + m_token = NTHCHILDSELECTORSEPARATOR; + } break; case CharacterDot: if (!isASCIIDigit(currentCharacter<SrcCharacterType>()[0])) break; - // Fall through to CharacterNumber. + FALLTHROUGH; // To CharacterNumber. case CharacterNumber: { bool dotSeen = (m_token == '.'); @@ -10993,7 +12446,6 @@ restartAfterComment: break; } -#if ENABLE(SVG) // Use SVG parser for numbers on SVG presentation attributes. if (m_context.mode == SVGAttributeMode) { // We need to take care of units like 'em' or 'ex'. @@ -11013,7 +12465,6 @@ restartAfterComment: if (!parseSVGNumber(tokenStart<SrcCharacterType>(), character - tokenStart<SrcCharacterType>(), yylval->number)) break; } else -#endif yylval->number = charactersToDouble(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>()); // Type of the function. @@ -11049,11 +12500,6 @@ restartAfterComment: parseIdentifier(result, resultString, hasEscape); m_token = IDENT; -#if ENABLE(CSS_VARIABLES) - if (cssVariablesEnabled() && isEqualToCSSCaseSensitiveIdentifier(tokenStart<SrcCharacterType>() + 1, "webkit-var") && tokenStart<SrcCharacterType>()[11] == '-' && isIdentifierStartAfterDash(tokenStart<SrcCharacterType>() + 12)) - m_token = VAR_DEFINITION; - else -#endif if (*currentCharacter<SrcCharacterType>() == '(') { m_token = FUNCTION; if (!hasEscape) @@ -11086,6 +12532,11 @@ restartAfterComment: } else if (currentCharacter<SrcCharacterType>()[0] == '-' && currentCharacter<SrcCharacterType>()[1] == '>') { currentCharacter<SrcCharacterType>() += 2; m_token = SGML_CD; + } else if (currentCharacter<SrcCharacterType>()[0] == '-') { + --currentCharacter<SrcCharacterType>(); + parseIdentifier(result, resultString, hasEscape); + m_token = CUSTOM_PROPERTY; + yylval->string = resultString; } else if (UNLIKELY(m_parsingMode == NthChildMode)) { // "-[0-9]+n" is always an NthChild. if (parseNthChild<SrcCharacterType>()) { @@ -11110,16 +12561,20 @@ restartAfterComment: // Might start with a '\n'. --currentCharacter<SrcCharacterType>(); do { - if (*currentCharacter<SrcCharacterType>() == '\n') + if (*currentCharacter<SrcCharacterType>() == '\n') { ++m_lineNumber; + m_columnOffsetForLine = currentCharacterOffset() + 1; + } ++currentCharacter<SrcCharacterType>(); } while (*currentCharacter<SrcCharacterType>() <= ' ' && (typesOfASCIICharacters[*currentCharacter<SrcCharacterType>()] == CharacterWhiteSpace)); break; - case CharacterEndMediaQuery: - if (m_parsingMode == MediaQueryMode) + case CharacterEndConditionQuery: { + bool isParsingCondition = m_parsingMode == MediaQueryMode || m_parsingMode == SupportsMode; + if (isParsingCondition) m_parsingMode = NormalMode; break; + } case CharacterEndNthChild: if (m_parsingMode == NthChildMode) @@ -11178,9 +12633,10 @@ restartAfterComment: if (*currentCharacter<SrcCharacterType>() == '*') { ++currentCharacter<SrcCharacterType>(); while (currentCharacter<SrcCharacterType>()[0] != '*' || currentCharacter<SrcCharacterType>()[1] != '/') { - if (*currentCharacter<SrcCharacterType>() == '\n') + if (*currentCharacter<SrcCharacterType>() == '\n') { ++m_lineNumber; - if (*currentCharacter<SrcCharacterType>() == '\0') { + m_columnOffsetForLine = currentCharacterOffset() + 1; + } else if (*currentCharacter<SrcCharacterType>() == '\0') { // Unterminated comments are simply ignored. currentCharacter<SrcCharacterType>() -= 2; break; @@ -11239,6 +12695,10 @@ restartAfterComment: parseIdentifier(result, yylval->string, hasEscape); m_token = IDENT; } + if (m_parsingMode == NthChildMode && m_token == IDENT && yylval->string.length() == 2 && equalLettersIgnoringASCIICase(yylval->string, "of")) { + m_parsingMode = NormalMode; + m_token = NTHCHILDSELECTORSEPARATOR; + } break; case CharacterXor: @@ -11270,161 +12730,18 @@ restartAfterComment: return token(); } -CSSParserSelector* CSSParser::createFloatingSelectorWithTagName(const QualifiedName& tagQName) -{ - CSSParserSelector* selector = new CSSParserSelector(tagQName); - m_floatingSelectors.add(selector); - return selector; -} - -CSSParserSelector* CSSParser::createFloatingSelector() -{ - CSSParserSelector* selector = new CSSParserSelector; - m_floatingSelectors.add(selector); - return selector; -} - -PassOwnPtr<CSSParserSelector> CSSParser::sinkFloatingSelector(CSSParserSelector* selector) -{ - if (selector) { - ASSERT(m_floatingSelectors.contains(selector)); - m_floatingSelectors.remove(selector); - } - return adoptPtr(selector); -} - -Vector<OwnPtr<CSSParserSelector> >* CSSParser::createFloatingSelectorVector() -{ - Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >; - m_floatingSelectorVectors.add(selectorVector); - return selectorVector; -} - -PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > CSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector) -{ - if (selectorVector) { - ASSERT(m_floatingSelectorVectors.contains(selectorVector)); - m_floatingSelectorVectors.remove(selectorVector); - } - return adoptPtr(selectorVector); -} - -CSSParserValueList* CSSParser::createFloatingValueList() -{ - CSSParserValueList* list = new CSSParserValueList; - m_floatingValueLists.add(list); - return list; -} - -PassOwnPtr<CSSParserValueList> CSSParser::sinkFloatingValueList(CSSParserValueList* list) -{ - if (list) { - ASSERT(m_floatingValueLists.contains(list)); - m_floatingValueLists.remove(list); - } - return adoptPtr(list); -} - -CSSParserFunction* CSSParser::createFloatingFunction() -{ - CSSParserFunction* function = new CSSParserFunction; - m_floatingFunctions.add(function); - return function; -} - -PassOwnPtr<CSSParserFunction> CSSParser::sinkFloatingFunction(CSSParserFunction* function) -{ - if (function) { - ASSERT(m_floatingFunctions.contains(function)); - m_floatingFunctions.remove(function); - } - return adoptPtr(function); -} - -CSSParserValue& CSSParser::sinkFloatingValue(CSSParserValue& value) -{ - if (value.unit == CSSParserValue::Function) { - ASSERT(m_floatingFunctions.contains(value.function)); - m_floatingFunctions.remove(value.function); - } - return value; -} - -MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values) -{ - m_floatingMediaQueryExp = MediaQueryExp::create(mediaFeature, values); - return m_floatingMediaQueryExp.get(); -} - -PassOwnPtr<MediaQueryExp> CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression) -{ - ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp); - return m_floatingMediaQueryExp.release(); -} - -Vector<OwnPtr<MediaQueryExp> >* CSSParser::createFloatingMediaQueryExpList() -{ - m_floatingMediaQueryExpList = adoptPtr(new Vector<OwnPtr<MediaQueryExp> >); - return m_floatingMediaQueryExpList.get(); -} - -PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > CSSParser::sinkFloatingMediaQueryExpList(Vector<OwnPtr<MediaQueryExp> >* list) -{ - ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList); - return m_floatingMediaQueryExpList.release(); -} - -MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const String& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions) -{ - m_floatingMediaQuery = adoptPtr(new MediaQuery(restrictor, mediaType, expressions)); - return m_floatingMediaQuery.get(); -} - -MediaQuery* CSSParser::createFloatingMediaQuery(PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions) -{ - return createFloatingMediaQuery(MediaQuery::None, "all", expressions); -} - -PassOwnPtr<MediaQuery> CSSParser::sinkFloatingMediaQuery(MediaQuery* query) -{ - ASSERT_UNUSED(query, query == m_floatingMediaQuery); - return m_floatingMediaQuery.release(); -} - -Vector<RefPtr<StyleKeyframe> >* CSSParser::createFloatingKeyframeVector() -{ - m_floatingKeyframeVector = adoptPtr(new Vector<RefPtr<StyleKeyframe> >()); - return m_floatingKeyframeVector.get(); -} - -PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > CSSParser::sinkFloatingKeyframeVector(Vector<RefPtr<StyleKeyframe> >* keyframeVector) -{ - ASSERT_UNUSED(keyframeVector, m_floatingKeyframeVector == keyframeVector); - return m_floatingKeyframeVector.release(); -} - -MediaQuerySet* CSSParser::createMediaQuerySet() -{ - RefPtr<MediaQuerySet> queries = MediaQuerySet::create(); - MediaQuerySet* result = queries.get(); - m_parsedMediaQuerySets.append(queries.release()); - return result; -} - -StyleRuleBase* CSSParser::createImportRule(const CSSParserString& url, MediaQuerySet* media) +RefPtr<StyleRuleBase> CSSParser::createImportRule(const CSSParserString& url, PassRefPtr<MediaQuerySet> media) { if (!media || !m_allowImportRules) { popRuleData(); - return 0; + return nullptr; } RefPtr<StyleRuleImport> rule = StyleRuleImport::create(url, media); - StyleRuleImport* result = rule.get(); - m_parsedRules.append(rule.release()); processAndAddNewRuleToSourceTreeIfNeeded(); - return result; + return rule; } -StyleRuleBase* CSSParser::createMediaRule(MediaQuerySet* media, RuleList* rules) +RefPtr<StyleRuleBase> CSSParser::createMediaRule(PassRefPtr<MediaQuerySet> media, RuleList* rules) { m_allowImportRules = m_allowNamespaceDeclarations = false; RefPtr<StyleRuleMedia> rule; @@ -11435,19 +12752,16 @@ StyleRuleBase* CSSParser::createMediaRule(MediaQuerySet* media, RuleList* rules) rule = StyleRuleMedia::create(MediaQuerySet::create(), emptyRules); } else rule = StyleRuleMedia::create(media, rules ? *rules : emptyRules); - StyleRuleMedia* result = rule.get(); - m_parsedRules.append(rule.release()); processAndAddNewRuleToSourceTreeIfNeeded(); - return result; + return rule; } -StyleRuleBase* CSSParser::createEmptyMediaRule(RuleList* rules) +RefPtr<StyleRuleBase> CSSParser::createEmptyMediaRule(RuleList* rules) { - return createMediaRule(MediaQuerySet::create().get(), rules); + return createMediaRule(MediaQuerySet::create(), rules); } -#if ENABLE(CSS3_CONDITIONAL_RULES) -StyleRuleBase* CSSParser::createSupportsRule(bool conditionIsSupported, RuleList* rules) +RefPtr<StyleRuleBase> CSSParser::createSupportsRule(bool conditionIsSupported, RuleList* rules) { m_allowImportRules = m_allowNamespaceDeclarations = false; @@ -11469,17 +12783,15 @@ StyleRuleBase* CSSParser::createSupportsRule(bool conditionIsSupported, RuleList rule = StyleRuleSupports::create(conditionText, conditionIsSupported, emptyRules); } - StyleRuleSupports* result = rule.get(); - m_parsedRules.append(rule.release()); processAndAddNewRuleToSourceTreeIfNeeded(); - return result; + return rule; } void CSSParser::markSupportsRuleHeaderStart() { if (!m_supportsRuleDataStack) - m_supportsRuleDataStack = adoptPtr(new RuleSourceDataList()); + m_supportsRuleDataStack = std::make_unique<RuleSourceDataList>(); RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(CSSRuleSourceData::SUPPORTS_RULE); data->ruleHeaderRange.start = tokenStartOffset(); @@ -11496,23 +12808,12 @@ void CSSParser::markSupportsRuleHeaderEnd() m_supportsRuleDataStack->last()->ruleHeaderRange.end = tokenStart<UChar>() - m_dataStart16.get(); } -PassRefPtr<CSSRuleSourceData> CSSParser::popSupportsRuleData() +RefPtr<CSSRuleSourceData> CSSParser::popSupportsRuleData() { ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty()); RefPtr<CSSRuleSourceData> data = m_supportsRuleDataStack->last(); m_supportsRuleDataStack->removeLast(); - return data.release(); -} - -#endif - -CSSParser::RuleList* CSSParser::createRuleList() -{ - OwnPtr<RuleList> list = adoptPtr(new RuleList); - RuleList* listPtr = list.get(); - - m_parsedRuleLists.append(list.release()); - return listPtr; + return data; } void CSSParser::processAndAddNewRuleToSourceTreeIfNeeded() @@ -11539,10 +12840,10 @@ void CSSParser::addNewRuleToSourceTree(PassRefPtr<CSSRuleSourceData> rule) PassRefPtr<CSSRuleSourceData> CSSParser::popRuleData() { if (!m_ruleSourceDataResult) - return 0; + return nullptr; ASSERT(!m_currentRuleDataStack->isEmpty()); - m_currentRuleData.clear(); + m_currentRuleData = nullptr; RefPtr<CSSRuleSourceData> data = m_currentRuleDataStack->last(); m_currentRuleDataStack->removeLast(); return data.release(); @@ -11552,14 +12853,15 @@ void CSSParser::syntaxError(const Location& location, SyntaxErrorType error) { if (!isLoggingErrors()) return; + StringBuilder builder; switch (error) { case PropertyDeclarationError: builder.appendLiteral("Invalid CSS property declaration at: "); break; - default: builder.appendLiteral("Unexpected CSS token: "); + break; } if (location.token.is8Bit()) @@ -11567,7 +12869,7 @@ void CSSParser::syntaxError(const Location& location, SyntaxErrorType error) else builder.append(location.token.characters16(), location.token.length()); - logError(builder.toString(), location.lineNumber); + logError(builder.toString(), location.lineNumber, location.columnNumber); m_ignoreErrorsInDeclaration = true; } @@ -11577,89 +12879,59 @@ bool CSSParser::isLoggingErrors() return m_logErrors && !m_ignoreErrorsInDeclaration; } -void CSSParser::logError(const String& message, int lineNumber) +void CSSParser::logError(const String& message, int lineNumber, int columnNumber) { - // FIXME: <http://webkit.org/b/114313> CSS Parser ConsoleMessage errors should include column numbers - PageConsole* console = m_styleSheet->singleOwnerDocument()->page()->console(); - console->addMessage(CSSMessageSource, WarningMessageLevel, message, m_styleSheet->baseURL().string(), lineNumber + 1, 0); + PageConsoleClient& console = m_styleSheet->singleOwnerDocument()->page()->console(); + console.addMessage(MessageSource::CSS, MessageLevel::Warning, message, m_styleSheet->baseURL().string(), lineNumber + 1, columnNumber + 1); } -StyleRuleKeyframes* CSSParser::createKeyframesRule(const String& name, PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > popKeyframes) +RefPtr<StyleRuleKeyframes> CSSParser::createKeyframesRule(const String& name, std::unique_ptr<Vector<RefPtr<StyleKeyframe>>> popKeyframes) { - OwnPtr<Vector<RefPtr<StyleKeyframe> > > keyframes = popKeyframes; + std::unique_ptr<Vector<RefPtr<StyleKeyframe>>> keyframes = WTFMove(popKeyframes); m_allowImportRules = m_allowNamespaceDeclarations = false; RefPtr<StyleRuleKeyframes> rule = StyleRuleKeyframes::create(); for (size_t i = 0; i < keyframes->size(); ++i) rule->parserAppendKeyframe(keyframes->at(i)); rule->setName(name); - StyleRuleKeyframes* rulePtr = rule.get(); - m_parsedRules.append(rule.release()); processAndAddNewRuleToSourceTreeIfNeeded(); - return rulePtr; + return rule; } -StyleRuleBase* CSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors) +RefPtr<StyleRuleBase> CSSParser::createStyleRule(Vector<std::unique_ptr<CSSParserSelector>>* selectors) { - StyleRule* result = 0; + RefPtr<StyleRule> rule; if (selectors) { - m_allowImportRules = m_allowNamespaceDeclarations = false; - RefPtr<StyleRule> rule = StyleRule::create(m_lastSelectorLineNumber); + m_allowImportRules = false; + m_allowNamespaceDeclarations = false; + rule = StyleRule::create(m_lastSelectorLineNumber, createStyleProperties()); rule->parserAdoptSelectorVector(*selectors); - if (m_hasFontFaceOnlyValues) - deleteFontFaceOnlyValues(); - rule->setProperties(createStylePropertySet()); - result = rule.get(); - m_parsedRules.append(rule.release()); processAndAddNewRuleToSourceTreeIfNeeded(); } else popRuleData(); clearProperties(); - return result; + return rule; } -StyleRuleBase* CSSParser::createFontFaceRule() +RefPtr<StyleRuleBase> CSSParser::createFontFaceRule() { m_allowImportRules = m_allowNamespaceDeclarations = false; for (unsigned i = 0; i < m_parsedProperties.size(); ++i) { CSSProperty& property = m_parsedProperties[i]; - if (property.id() == CSSPropertyFontVariant && property.value()->isPrimitiveValue()) - property.wrapValueInCommaSeparatedList(); - else if (property.id() == CSSPropertyFontFamily && (!property.value()->isValueList() || static_cast<CSSValueList*>(property.value())->length() != 1)) { + if (property.id() == CSSPropertyFontFamily && (!is<CSSValueList>(*property.value()) || downcast<CSSValueList>(*property.value()).length() != 1)) { // Unlike font-family property, font-family descriptor in @font-face rule // has to be a value list with exactly one family name. It cannot have a // have 'initial' value and cannot 'inherit' from parent. // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc clearProperties(); popRuleData(); - return 0; + return nullptr; } } - RefPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create(); - rule->setProperties(createStylePropertySet()); + RefPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create(createStyleProperties()); clearProperties(); - StyleRuleFontFace* result = rule.get(); - m_parsedRules.append(rule.release()); - processAndAddNewRuleToSourceTreeIfNeeded(); - return result; -} - -#if ENABLE(SHADOW_DOM) -StyleRuleBase* CSSParser::createHostRule(RuleList* rules) -{ - m_allowImportRules = m_allowNamespaceDeclarations = false; - RefPtr<StyleRuleHost> rule; - if (rules) - rule = StyleRuleHost::create(*rules); - else { - RuleList emptyRules; - rule = StyleRuleHost::create(emptyRules); - } - StyleRuleHost* result = rule.get(); - m_parsedRules.append(rule.release()); processAndAddNewRuleToSourceTreeIfNeeded(); - return result; + return rule; } -#endif void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri) { @@ -11678,30 +12950,27 @@ QualifiedName CSSParser::determineNameInNamespace(const AtomicString& prefix, co return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix)); } -CSSParserSelector* CSSParser::rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector* specifiers) +void CSSParser::rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector& specifiers) { - if (m_defaultNamespace != starAtom || specifiers->isCustomPseudoElement()) - return rewriteSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true); - return specifiers; + if (m_defaultNamespace != starAtom || specifiers.isCustomPseudoElement()) + rewriteSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true); } -CSSParserSelector* CSSParser::rewriteSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule) +void CSSParser::rewriteSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector& specifiers, bool tagIsForNamespaceRule) { AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace; QualifiedName tag(namespacePrefix, elementName, determinedNamespace); - if (!specifiers->isCustomPseudoElement()) { + if (!specifiers.isCustomPseudoElement()) { if (tag == anyQName()) - return specifiers; -#if ENABLE(VIDEO_TRACK) - if (!(specifiers->pseudoType() == CSSSelector::PseudoCue)) -#endif - specifiers->prependTagSelector(tag, tagIsForNamespaceRule); - return specifiers; + return; + if (!specifiers.isPseudoElementCueFunction()) + specifiers.prependTagSelector(tag, tagIsForNamespaceRule); + return; } - CSSParserSelector* lastShadowDescendant = specifiers; - CSSParserSelector* history = specifiers; + CSSParserSelector* lastShadowDescendant = &specifiers; + CSSParserSelector* history = &specifiers; while (history->tagHistory()) { history = history->tagHistory(); if (history->isCustomPseudoElement() || history->hasShadowDescendant()) @@ -11711,83 +12980,81 @@ CSSParserSelector* CSSParser::rewriteSpecifiersWithElementName(const AtomicStrin if (lastShadowDescendant->tagHistory()) { if (tag != anyQName()) lastShadowDescendant->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule); - return specifiers; + return; } // For shadow-ID pseudo-elements to be correctly matched, the ShadowDescendant combinator has to be used. // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*'). - OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag)); - lastShadowDescendant->setTagHistory(elementNameSelector.release()); + lastShadowDescendant->setTagHistory(std::make_unique<CSSParserSelector>(tag)); lastShadowDescendant->setRelation(CSSSelector::ShadowDescendant); - return specifiers; } -CSSParserSelector* CSSParser::rewriteSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier) +std::unique_ptr<CSSParserSelector> CSSParser::rewriteSpecifiers(std::unique_ptr<CSSParserSelector> specifiers, std::unique_ptr<CSSParserSelector> newSpecifier) { -#if ENABLE(VIDEO_TRACK) - if (newSpecifier->isCustomPseudoElement() || newSpecifier->pseudoType() == CSSSelector::PseudoCue) { -#else - if (newSpecifier->isCustomPseudoElement()) { -#endif + if (newSpecifier->isCustomPseudoElement() || newSpecifier->isPseudoElementCueFunction()) { // Unknown pseudo element always goes at the top of selector chain. - newSpecifier->appendTagHistory(CSSSelector::ShadowDescendant, sinkFloatingSelector(specifiers)); + newSpecifier->appendTagHistory(CSSSelector::ShadowDescendant, WTFMove(specifiers)); return newSpecifier; } if (specifiers->isCustomPseudoElement()) { // Specifiers for unknown pseudo element go right behind it in the chain. - specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::ShadowDescendant); + specifiers->insertTagHistory(CSSSelector::SubSelector, WTFMove(newSpecifier), CSSSelector::ShadowDescendant); return specifiers; } - specifiers->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier)); + specifiers->appendTagHistory(CSSSelector::SubSelector, WTFMove(newSpecifier)); return specifiers; } -StyleRuleBase* CSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector) +RefPtr<StyleRuleBase> CSSParser::createPageRule(std::unique_ptr<CSSParserSelector> pageSelector) { // FIXME: Margin at-rules are ignored. m_allowImportRules = m_allowNamespaceDeclarations = false; - StyleRulePage* pageRule = 0; + RefPtr<StyleRulePage> rule; if (pageSelector) { - RefPtr<StyleRulePage> rule = StyleRulePage::create(); - Vector<OwnPtr<CSSParserSelector> > selectorVector; - selectorVector.append(pageSelector); + rule = StyleRulePage::create(createStyleProperties()); + Vector<std::unique_ptr<CSSParserSelector>> selectorVector; + selectorVector.append(WTFMove(pageSelector)); rule->parserAdoptSelectorVector(selectorVector); - rule->setProperties(createStylePropertySet()); - pageRule = rule.get(); - m_parsedRules.append(rule.release()); processAndAddNewRuleToSourceTreeIfNeeded(); } else popRuleData(); clearProperties(); - return pageRule; + return rule; } -void CSSParser::setReusableRegionSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectors) +std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> CSSParser::createSelectorVector() { - if (selectors) - m_reusableRegionSelectorVector.swap(*selectors); + if (m_recycledSelectorVector) { + m_recycledSelectorVector->shrink(0); + return WTFMove(m_recycledSelectorVector); + } + return std::make_unique<Vector<std::unique_ptr<CSSParserSelector>>>(); } -StyleRuleBase* CSSParser::createRegionRule(Vector<OwnPtr<CSSParserSelector> >* regionSelector, RuleList* rules) +void CSSParser::recycleSelectorVector(std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> vector) +{ + if (vector && !m_recycledSelectorVector) + m_recycledSelectorVector = WTFMove(vector); +} + +RefPtr<StyleRuleBase> CSSParser::createRegionRule(Vector<std::unique_ptr<CSSParserSelector>>* regionSelector, RuleList* rules) { if (!cssRegionsEnabled() || !regionSelector || !rules) { popRuleData(); - return 0; + return nullptr; } m_allowImportRules = m_allowNamespaceDeclarations = false; RefPtr<StyleRuleRegion> regionRule = StyleRuleRegion::create(regionSelector, *rules); - StyleRuleRegion* result = regionRule.get(); - m_parsedRules.append(regionRule.release()); if (isExtractingSourceData()) addNewRuleToSourceTree(CSSRuleSourceData::createUnknown()); - return result; + return regionRule; } -StyleRuleBase* CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */) +void CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */) { // FIXME: Implement margin at-rule here, using: // - marginBox: margin box @@ -11795,7 +13062,6 @@ StyleRuleBase* CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* margi // 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. endDeclarationsForMarginBox(); - return 0; // until this method is implemented. } void CSSParser::startDeclarationsForMarginBox() @@ -11809,56 +13075,40 @@ void CSSParser::endDeclarationsForMarginBox() m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES; } -void CSSParser::deleteFontFaceOnlyValues() -{ - ASSERT(m_hasFontFaceOnlyValues); - for (unsigned i = 0; i < m_parsedProperties.size();) { - CSSProperty& property = m_parsedProperties[i]; - if (property.id() == CSSPropertyFontVariant && property.value()->isValueList()) { - m_parsedProperties.remove(i); - continue; - } - ++i; - } -} - -StyleKeyframe* CSSParser::createKeyframe(CSSParserValueList* keys) +RefPtr<StyleKeyframe> CSSParser::createKeyframe(CSSParserValueList& keys) { // Create a key string from the passed keys StringBuilder keyString; - for (unsigned i = 0; i < keys->size(); ++i) { + for (unsigned i = 0; i < keys.size(); ++i) { // Just as per the comment below, we ignore keyframes with // invalid key values (plain numbers or unknown identifiers) // marked as CSSPrimitiveValue::CSS_UNKNOWN during parsing. - if (keys->valueAt(i)->unit == CSSPrimitiveValue::CSS_UNKNOWN) { + if (keys.valueAt(i)->unit == CSSPrimitiveValue::CSS_UNKNOWN) { clearProperties(); - return 0; + return nullptr; } - ASSERT(keys->valueAt(i)->unit == CSSPrimitiveValue::CSS_NUMBER); - float key = static_cast<float>(keys->valueAt(i)->fValue); + ASSERT(keys.valueAt(i)->unit == CSSPrimitiveValue::CSS_NUMBER); + float key = static_cast<float>(keys.valueAt(i)->fValue); if (key < 0 || key > 100) { // As per http://www.w3.org/TR/css3-animations/#keyframes, // "If a keyframe selector specifies negative percentage values // or values higher than 100%, then the keyframe will be ignored." clearProperties(); - return 0; + return nullptr; } if (i != 0) keyString.append(','); - keyString.append(String::number(key)); + keyString.appendNumber(key); keyString.append('%'); } - RefPtr<StyleKeyframe> keyframe = StyleKeyframe::create(); + RefPtr<StyleKeyframe> keyframe = StyleKeyframe::create(createStyleProperties()); keyframe->setKeyText(keyString.toString()); - keyframe->setProperties(createStylePropertySet()); clearProperties(); - StyleKeyframe* keyframePtr = keyframe.get(); - m_parsedKeyframes.append(keyframe.release()); - return keyframePtr; + return keyframe; } void CSSParser::invalidBlockHit() @@ -11978,7 +13228,7 @@ void CSSParser::markRuleHeaderEnd() void CSSParser::markSelectorStart() { - if (!isExtractingSourceData()) + if (!isExtractingSourceData() || m_nestedSelectorLevel) return; ASSERT(!m_selectorRange.end); @@ -11987,7 +13237,7 @@ void CSSParser::markSelectorStart() void CSSParser::markSelectorEnd() { - if (!isExtractingSourceData()) + if (!isExtractingSourceData() || m_nestedSelectorLevel) return; ASSERT(!m_selectorRange.end); ASSERT(m_currentRuleDataStack->size()); @@ -12002,7 +13252,7 @@ void CSSParser::markRuleBodyStart() { if (!isExtractingSourceData()) return; - m_currentRuleData.clear(); + m_currentRuleData = nullptr; unsigned offset = tokenStartOffset(); if (tokenStartChar() == '{') ++offset; // Skip the rule body opening brace. @@ -12044,7 +13294,7 @@ void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed) // This stuff is only executed when the style data retrieval is requested by client. const unsigned start = m_propertyRange.start; const unsigned end = m_propertyRange.end; - ASSERT(start < end); + ASSERT_WITH_SECURITY_IMPLICATION(start < end); String propertyString; if (is8BitSource()) propertyString = String(m_dataStart8.get() + start, end - start).stripWhiteSpace(); @@ -12066,29 +13316,26 @@ void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed) } #if ENABLE(CSS_DEVICE_ADAPTATION) -StyleRuleBase* CSSParser::createViewportRule() +PassRefPtr<StyleRuleBase> CSSParser::createViewportRule() { m_allowImportRules = m_allowNamespaceDeclarations = false; - RefPtr<StyleRuleViewport> rule = StyleRuleViewport::create(); - - rule->setProperties(createStylePropertySet()); + RefPtr<StyleRuleViewport> rule = StyleRuleViewport::create(createStyleProperties()); clearProperties(); - StyleRuleViewport* result = rule.get(); - m_parsedRules.append(rule.release()); processAndAddNewRuleToSourceTreeIfNeeded(); - return result; + return rule.release(); } bool CSSParser::parseViewportProperty(CSSPropertyID propId, bool important) { - CSSParserValue* value = m_valueList->current(); - if (!value) + if (!m_valueList->current()) return false; - CSSValueID id = value->id; + ValueWithCalculation valueWithCalculation(*m_valueList->current()); + + CSSValueID id = valueWithCalculation.value().id; bool validPrimitive = false; switch (propId) { @@ -12099,7 +13346,7 @@ bool CSSParser::parseViewportProperty(CSSPropertyID propId, bool important) if (id == CSSValueAuto || id == CSSValueDeviceWidth || id == CSSValueDeviceHeight) validPrimitive = true; else - validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg)); + validPrimitive = (!id && validateUnit(valueWithCalculation, FLength | FPercent | FNonNeg)); break; case CSSPropertyWidth: // shorthand return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMaxWidth, important); @@ -12111,7 +13358,7 @@ bool CSSParser::parseViewportProperty(CSSPropertyID propId, bool important) if (id == CSSValueAuto) validPrimitive = true; else - validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg)); + validPrimitive = (!id && validateUnit(valueWithCalculation, FNumber | FPercent | FNonNeg)); break; case CSSPropertyUserZoom: // zoom | fixed if (id == CSSValueZoom || id == CSSValueFixed) @@ -12126,7 +13373,7 @@ bool CSSParser::parseViewportProperty(CSSPropertyID propId, bool important) RefPtr<CSSValue> parsedValue; if (validPrimitive) { - parsedValue = parseValidPrimitive(id, value); + parsedValue = parseValidPrimitive(id, valueWithCalculation); m_valueList->next(); } @@ -12179,7 +13426,7 @@ static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned l #if ENABLE(LEGACY_CSS_VENDOR_PREFIXES) // If the prefix is -apple- or -khtml-, change it to -webkit-. // This makes the string one character longer. - if (RuntimeEnabledFeatures::legacyCSSVendorPrefixesEnabled() + if (RuntimeEnabledFeatures::sharedFeatures().legacyCSSVendorPrefixesEnabled() && (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-"))) { memmove(buffer + 7, buffer + 6, length + 1 - 6); memcpy(buffer, "-webkit", 7); @@ -12192,16 +13439,7 @@ static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned l } const Property* hashTableEntry = findProperty(name, length); - const CSSPropertyID propertyID = hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid; - - static const int cssPropertyHistogramSize = numCSSProperties; - if (hasPrefix(buffer, length, "-webkit-") && propertyID != CSSPropertyInvalid) { - int histogramValue = propertyID - firstCSSProperty; - ASSERT(0 <= histogramValue && histogramValue < cssPropertyHistogramSize); - HistogramSupport::histogramEnumeration("CSS.PrefixUsage", histogramValue, cssPropertyHistogramSize); - } - - return propertyID; + return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid; } CSSPropertyID cssPropertyID(const String& string) @@ -12240,6 +13478,17 @@ void cssPropertyNameIOSAliasing(const char* propertyName, const char*& propertyN } #endif +static bool isAppleLegacyCssValueKeyword(const char* valueKeyword, unsigned length) +{ + static const char* applePrefix = "-apple-"; + static const char* appleSystemPrefix = "-apple-system"; + static const char* appleWirelessPlaybackTargetActive = getValueName(CSSValueAppleWirelessPlaybackTargetActive); + + return hasPrefix(valueKeyword, length, applePrefix) + && !hasPrefix(valueKeyword, length, appleSystemPrefix) + && !WTF::equal(reinterpret_cast<const LChar*>(valueKeyword), reinterpret_cast<const LChar*>(appleWirelessPlaybackTargetActive), length); +} + template <typename CharacterType> static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length) { @@ -12256,7 +13505,9 @@ static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned if (buffer[0] == '-') { // If the prefix is -apple- or -khtml-, change it to -webkit-. // This makes the string one character longer. - if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) { + // On iOS we don't want to change values starting with -apple-system to -webkit-system. + // FIXME: Remove this mangling without breaking the web. + if (isAppleLegacyCssValueKeyword(buffer, length) || hasPrefix(buffer, length, "-khtml-")) { memmove(buffer + 7, buffer + 6, length + 1 - 6); memcpy(buffer, "-webkit", 7); ++length; @@ -12439,8 +13690,10 @@ bool isValidNthToken(const CSSParserString& token) // However, since the {ident} rule precedes the {nth} rule, some of those // tokens are identified as string literal. Furthermore we need to accept // "odd" and "even" which does not match to an+b. - return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even") - || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n"); + return equalLettersIgnoringASCIICase(token, "odd") + || equalLettersIgnoringASCIICase(token, "even") + || equalLettersIgnoringASCIICase(token, "n") + || equalLettersIgnoringASCIICase(token, "-n"); } } |